* remove little unused code

* code cleanup
This commit is contained in:
giantpune 2010-09-18 23:16:05 +00:00
parent e1a36e8988
commit 9e79c9d99b
326 changed files with 87736 additions and 80266 deletions

View File

@ -2,8 +2,8 @@
<app version="1"> <app version="1">
<name> USB Loader GX</name> <name> USB Loader GX</name>
<coder>USB Loader GX Team</coder> <coder>USB Loader GX Team</coder>
<version>1.0 r950</version> <version>1.0 r951</version>
<release_date>201009182245</release_date> <release_date>201009182308</release_date>
<short_description>Loads games from USB-devices</short_description> <short_description>Loads games from USB-devices</short_description>
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times. <long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller. The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.

BIN
data/magic_patcher.o Normal file

Binary file not shown.

View File

@ -37,7 +37,8 @@
* *
* Font face character glyph relevant data structure. * Font face character glyph relevant data structure.
*/ */
typedef struct ftgxCharData_ { typedef struct ftgxCharData_
{
int16_t renderOffsetX; /**< Texture X axis bearing offset. */ int16_t renderOffsetX; /**< Texture X axis bearing offset. */
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */ uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */ uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
@ -56,7 +57,8 @@ typedef struct ftgxCharData_ {
* *
* Offset structure which hold both a maximum and minimum value. * Offset structure which hold both a maximum and minimum value.
*/ */
typedef struct ftgxDataOffset_ { typedef struct ftgxDataOffset_
{
int16_t ascender; /**< Maximum data offset. */ int16_t ascender; /**< Maximum data offset. */
int16_t descender; /**< Minimum data offset. */ int16_t descender; /**< Minimum data offset. */
int16_t max; /**< Maximum data offset. */ int16_t max; /**< Maximum data offset. */

View File

@ -121,7 +121,8 @@ bool ZipFile::ExtractAll(const char *dest)
done += ret; done += ret;
} while(done < uncompressed_size); }
while ( done < uncompressed_size );
fclose( pfile ); fclose( pfile );
unzCloseCurrentFile( File ); unzCloseCurrentFile( File );

View File

@ -15,7 +15,8 @@
* *
* Initializes the Wii's audio subsystem * Initializes the Wii's audio subsystem
***************************************************************************/ ***************************************************************************/
void InitAudio() { void InitAudio()
{
AUDIO_Init( NULL ); AUDIO_Init( NULL );
ASND_Init(); ASND_Init();
ASND_Pause( 0 ); ASND_Pause( 0 );
@ -27,7 +28,8 @@ void InitAudio() {
* Shuts down audio subsystem. Useful to avoid unpleasant sounds if a * Shuts down audio subsystem. Useful to avoid unpleasant sounds if a
* crash occurs during shutdown. * crash occurs during shutdown.
***************************************************************************/ ***************************************************************************/
void ShutdownAudio() { void ShutdownAudio()
{
ASND_Pause( 1 ); ASND_Pause( 1 );
ASND_End(); ASND_End();
} }

View File

@ -552,7 +552,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
file = fopen( src, "rb" ); file = fopen( src, "rb" );
if (file==NULL){ if ( file == NULL )
{
return NULL; return NULL;
} }
@ -569,7 +570,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
unsigned char * buffer = malloc( blksize ); unsigned char * buffer = malloc( blksize );
if(buffer == NULL){ if ( buffer == NULL )
{
//no memory //no memory
fclose( file ); fclose( file );
return NULL; return NULL;
@ -580,7 +582,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
read = fread( buffer, 1, blksize, file ); read = fread( buffer, 1, blksize, file );
( void )auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */ ( void )auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
} while(read > 0); }
while ( read > 0 );
fclose( file ); fclose( file );
free( buffer ); free( buffer );

View File

@ -39,7 +39,8 @@ s32 dump_banner(const u8* discid,const char * dest)
ret = WDVD_OpenPartition( offset ); ret = WDVD_OpenPartition( offset );
if (ret < 0) { if ( ret < 0 )
{
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret); //printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
return ret; return ret;
} }

View File

@ -15,7 +15,8 @@ GuiBanner::GuiBanner(const char *tplfilepath)
FILE *tplfp = fopen( tplfilepath, "rb" ); FILE *tplfp = fopen( tplfilepath, "rb" );
if(tplfp !=NULL) { if ( tplfp != NULL )
{
unsigned short heighttemp = 0; unsigned short heighttemp = 0;
unsigned short widthtemp = 0; unsigned short widthtemp = 0;
@ -27,7 +28,8 @@ GuiBanner::GuiBanner(const char *tplfilepath)
tplfilesize = ftell ( tplfp ); tplfilesize = ftell ( tplfp );
rewind ( tplfp ); rewind ( tplfp );
memory = memalign( 32, tplfilesize ); memory = memalign( 32, tplfilesize );
if(!memory) { if ( !memory )
{
fclose( tplfp ); fclose( tplfp );
return; return;
} }
@ -38,13 +40,15 @@ GuiBanner::GuiBanner(const char *tplfilepath)
int ret; int ret;
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize ); ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
if(ret < 0) { if ( ret < 0 )
{
free( memory ); free( memory );
memory = NULL; memory = NULL;
return; return;
} }
ret = TPL_GetTexture( &tplfile, 0, &texObj ); ret = TPL_GetTexture( &tplfile, 0, &texObj );
if(ret < 0) { if ( ret < 0 )
{
free( memory ); free( memory );
memory = NULL; memory = NULL;
return; return;
@ -56,7 +60,9 @@ GuiBanner::GuiBanner(const char *tplfilepath)
widescreen = 0; widescreen = 0;
filecheck = true; filecheck = true;
} else { }
else
{
filecheck = false; filecheck = false;
fclose( tplfp ); fclose( tplfp );
} }
@ -76,13 +82,15 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
int ret; int ret;
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize ); ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
if(ret < 0) { if ( ret < 0 )
{
free( memory ); free( memory );
memory = NULL; memory = NULL;
return; return;
} }
ret = TPL_GetTexture( &tplfile, 0, &texObj ); ret = TPL_GetTexture( &tplfile, 0, &texObj );
if(ret < 0) { if ( ret < 0 )
{
free( memory ); free( memory );
memory = NULL; memory = NULL;
return; return;
@ -94,7 +102,8 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
GuiBanner::~GuiBanner() GuiBanner::~GuiBanner()
{ {
if(memory != NULL) { if ( memory != NULL )
{
free( memory ); free( memory );
memory = NULL; memory = NULL;
} }

View File

@ -72,7 +72,8 @@ void md5(u8 *data, u32 len, u8 *hash)
} }
typedef struct { typedef struct
{
u8 zeroes[0x40]; u8 zeroes[0x40];
u32 imet; // "IMET" u32 imet; // "IMET"
u8 zero_six_zero_three[8]; // fixed, unknown purpose u8 zero_six_zero_three[8]; // fixed, unknown purpose
@ -89,7 +90,8 @@ typedef struct {
u8 crypto[0x10]; u8 crypto[0x10];
} imet_data_t; } imet_data_t;
typedef struct { typedef struct
{
u32 imd5_tag; // 0x494D4435 "IMD5"; u32 imd5_tag; // 0x494D4435 "IMD5";
u32 size; // size of the rest of part B, starting from next field. u32 size; // size of the rest of part B, starting from next field.
u8 zeroes[8]; u8 zeroes[8];
@ -148,13 +150,16 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
out_ptr = decompressed_data; out_ptr = decompressed_data;
while (in_ptr < data_end) { while ( in_ptr < data_end )
{
int bit; int bit;
u8 bitmask = *in_ptr; u8 bitmask = *in_ptr;
in_ptr++; in_ptr++;
for (bit = 0x80; bit != 0; bit >>= 1) { for ( bit = 0x80; bit != 0; bit >>= 1 )
if (bitmask & bit) { {
if ( bitmask & bit )
{
// Next section is compressed // Next section is compressed
u8 rep_length; u8 rep_length;
u16 rep_offset; u16 rep_offset;
@ -164,14 +169,17 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
in_ptr++; in_ptr++;
rep_offset = *in_ptr | ( rep_offset << 8 ); rep_offset = *in_ptr | ( rep_offset << 8 );
in_ptr++; in_ptr++;
if (out_ptr-decompressed_data < rep_offset) { if ( out_ptr - decompressed_data < rep_offset )
{
return NULL; return NULL;
} }
for ( ; rep_length > 0; rep_length--) { for ( ; rep_length > 0; rep_length-- )
{
*out_ptr = out_ptr[-rep_offset-1]; *out_ptr = out_ptr[-rep_offset-1];
out_ptr++; out_ptr++;
if (out_ptr >= out_end) { if ( out_ptr >= out_end )
{
// Need to grow buffer // Need to grow buffer
decompressed_data = realloc( decompressed_data, unpacked_size * 2 ); decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
out_ptr = decompressed_data + unpacked_size; out_ptr = decompressed_data + unpacked_size;
@ -179,11 +187,14 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
out_end = decompressed_data + unpacked_size; out_end = decompressed_data + unpacked_size;
} }
} }
} else { }
else
{
// Just copy byte // Just copy byte
*out_ptr = *in_ptr; *out_ptr = *in_ptr;
out_ptr++; out_ptr++;
if (out_ptr >= out_end) { if ( out_ptr >= out_end )
{
// Need to grow buffer // Need to grow buffer
decompressed_data = realloc( decompressed_data, unpacked_size * 2 ); decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
out_ptr = decompressed_data + unpacked_size; out_ptr = decompressed_data + unpacked_size;
@ -209,22 +220,26 @@ static int write_imd5_lz77(u8* data, size_t size, char* outname)
size_t decompressed_size; size_t decompressed_size;
tag = be32( ( u8* ) & header->imd5_tag ); tag = be32( ( u8* ) & header->imd5_tag );
if (tag != 0x494D4435) { if ( tag != 0x494D4435 )
{
return -4; return -4;
} }
md5( data + 32, size - 32, md5_calc ); md5( data + 32, size - 32, md5_calc );
if (memcmp(&header->md5, md5_calc, 0x10)) { if ( memcmp( &header->md5, md5_calc, 0x10 ) )
{
return -5; return -5;
} }
size_in_imd5 = be32( ( u8* ) & header->size ); size_in_imd5 = be32( ( u8* ) & header->size );
if (size_in_imd5 != size - 32) { if ( size_in_imd5 != size - 32 )
{
return -6; return -6;
} }
tag = be32( ( u8* ) & header->payload_tag ); tag = be32( ( u8* ) & header->payload_tag );
if (tag == 0x4C5A3737) { if ( tag == 0x4C5A3737 )
{
// "LZ77" - uncompress // "LZ77" - uncompress
decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size ); decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size );
if ( decompressed_data == NULL ) if ( decompressed_data == NULL )
@ -233,7 +248,9 @@ static int write_imd5_lz77(u8* data, size_t size, char* outname)
//printf(", uncompressed %d bytes, md5 ok", decompressed_size); //printf(", uncompressed %d bytes, md5 ok", decompressed_size);
free( decompressed_data ); free( decompressed_data );
} else { }
else
{
write_file( &header->payload_tag, size - 32, outname ); write_file( &header->payload_tag, size - 32, outname );
//printf(", md5 ok"); //printf(", md5 ok");
} }
@ -257,7 +274,8 @@ static int do_U8_archive(FILE *fp)
fread( &header, 1, sizeof header, fp ); fread( &header, 1, sizeof header, fp );
tag = be32( ( u8* ) & header.tag ); tag = be32( ( u8* ) & header.tag );
if (tag != 0x55AA382D) { if ( tag != 0x55AA382D )
{
return -1; return -1;
} }
@ -275,7 +293,8 @@ static int do_U8_archive(FILE *fp)
fread( string_table, 1, rest_size, fp ); fread( string_table, 1, rest_size, fp );
current_offset = data_offset; current_offset = data_offset;
for (i = 0; i < num_nodes; i++) { for ( i = 0; i < num_nodes; i++ )
{
U8_node* node = &nodes[i]; U8_node* node = &nodes[i];
u16 type = be16( ( u8* ) & node->type ); u16 type = be16( ( u8* ) & node->type );
u16 name_offset = be16( ( u8* ) & node->name_offset ); u16 name_offset = be16( ( u8* ) & node->name_offset );
@ -284,25 +303,31 @@ static int do_U8_archive(FILE *fp)
char* name = ( char* ) & string_table[name_offset]; char* name = ( char* ) & string_table[name_offset];
u8* file_data; u8* file_data;
if (type == 0x0100) { if ( type == 0x0100 )
{
// Directory // Directory
mkdir( name, 0777 ); mkdir( name, 0777 );
chdir( name ); chdir( name );
dir_stack[++dir_index] = size; dir_stack[++dir_index] = size;
//printf("%*s%s/\n", dir_index, "", name); //printf("%*s%s/\n", dir_index, "", name);
} else { }
else
{
// Normal file // Normal file
u8 padding[32]; u8 padding[32];
if (type != 0x0000) { if ( type != 0x0000 )
{
free( string_table ); free( string_table );
return -2; return -2;
} }
if (current_offset < my_data_offset) { if ( current_offset < my_data_offset )
{
int diff = my_data_offset - current_offset; int diff = my_data_offset - current_offset;
if (diff > 32) { if ( diff > 32 )
{
free( string_table ); free( string_table );
return -3; return -3;
} }
@ -316,14 +341,16 @@ static int do_U8_archive(FILE *fp)
int result; int result;
result = write_imd5_lz77( file_data, size, name ); result = write_imd5_lz77( file_data, size, name );
if ( result < 0 ) if ( result < 0 )
{free(string_table); {
free( string_table );
return result; return result;
} }
//printf(")\n"); //printf(")\n");
current_offset += size; current_offset += size;
} }
while (dir_stack[dir_index] == i+2 && dir_index > 0) { while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
{
chdir( ".." ); chdir( ".." );
dir_index--; dir_index--;
} }
@ -357,7 +384,8 @@ void do_U8_archivebanner(FILE *fp)
fread( &header, 1, sizeof header, fp ); fread( &header, 1, sizeof header, fp );
tag = be32( ( u8* ) & header.tag ); tag = be32( ( u8* ) & header.tag );
if (tag != 0x55AA382D) { if ( tag != 0x55AA382D )
{
//printf("No U8 tag"); //printf("No U8 tag");
exit( 0 ); exit( 0 );
} }
@ -375,7 +403,8 @@ void do_U8_archivebanner(FILE *fp)
string_table = malloc( rest_size ); string_table = malloc( rest_size );
fread( string_table, 1, rest_size, fp ); fread( string_table, 1, rest_size, fp );
for (i = 0; i < num_nodes; i++) { for ( i = 0; i < num_nodes; i++ )
{
U8_node* node = &nodes[i]; U8_node* node = &nodes[i];
u16 type = be16( ( u8* ) & node->type ); u16 type = be16( ( u8* ) & node->type );
u16 name_offset = be16( ( u8* ) & node->name_offset ); u16 name_offset = be16( ( u8* ) & node->name_offset );
@ -384,16 +413,20 @@ void do_U8_archivebanner(FILE *fp)
char* name = ( char* ) & string_table[name_offset]; char* name = ( char* ) & string_table[name_offset];
u8* file_data; u8* file_data;
if (type == 0x0100) { if ( type == 0x0100 )
{
// Directory // Directory
mkdir( name, 0777 ); mkdir( name, 0777 );
chdir( name ); chdir( name );
dir_stack[++dir_index] = size; dir_stack[++dir_index] = size;
//printf("%*s%s/\n", dir_index, "", name); //printf("%*s%s/\n", dir_index, "", name);
} else { }
else
{
// Normal file // Normal file
if (type != 0x0000) { if ( type != 0x0000 )
{
printf( "Unknown type" ); printf( "Unknown type" );
exit( 0 ); exit( 0 );
} }
@ -406,7 +439,8 @@ void do_U8_archivebanner(FILE *fp)
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size); //printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
} }
while (dir_stack[dir_index] == i+2 && dir_index > 0) { while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
{
chdir( ".." ); chdir( ".." );
dir_index--; dir_index--;
} }

View File

@ -23,7 +23,8 @@ extern GuiWindow * mainWindow;
/**************************************************************************** /****************************************************************************
* CheatMenu * CheatMenu
***************************************************************************/ ***************************************************************************/
int CheatMenu(const char * gameID) { int CheatMenu( const char * gameID )
{
int choice = 0; int choice = 0;
bool exit = false; bool exit = false;
int ret = 1; int ret = 1;
@ -65,7 +66,8 @@ int CheatMenu(const char * gameID) {
int download = 0; int download = 0;
switch (check) { switch ( check )
{
case -1: case -1:
WindowPrompt( tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ) ); WindowPrompt( tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ) );
break; break;
@ -92,7 +94,8 @@ int CheatMenu(const char * gameID) {
titleTxt.SetMaxWidth( 350, SCROLL_HORIZONTAL ); titleTxt.SetMaxWidth( 350, SCROLL_HORIZONTAL );
titleTxt.SetPosition( 12, 40 ); titleTxt.SetPosition( 12, 40 );
for (int i = 0; i <= cntcheats; i++) { for ( int i = 0; i <= cntcheats; i++ )
{
cheatslst.SetValue( i, "%s", c.getCheatName( i ).c_str() ); cheatslst.SetValue( i, "%s", c.getCheatName( i ).c_str() );
cheatslst.SetName( i, "OFF" ); cheatslst.SetName( i, "OFF" );
} }
@ -109,34 +112,46 @@ int CheatMenu(const char * gameID) {
mainWindow->Append( &w ); mainWindow->Append( &w );
ResumeGui(); ResumeGui();
while (!exit) { while ( !exit )
{
VIDEO_WaitVSync (); VIDEO_WaitVSync ();
ret = chtBrowser.GetClickedOption(); ret = chtBrowser.GetClickedOption();
if (ret != -1) { if ( ret != -1 )
{
const char *strCheck = cheatslst.GetName( ret ); const char *strCheck = cheatslst.GetName( ret );
if (strncmp(strCheck,"ON",2) == 0) { if ( strncmp( strCheck, "ON", 2 ) == 0 )
{
cheatslst.SetName( ret, "%s", "OFF" ); cheatslst.SetName( ret, "%s", "OFF" );
} else if (strncmp(strCheck,"OFF",3) == 0) { }
else if ( strncmp( strCheck, "OFF", 3 ) == 0 )
{
cheatslst.SetName( ret, "%s", "ON" ); cheatslst.SetName( ret, "%s", "ON" );
} }
} }
if (createBtn.GetState() == STATE_CLICKED) { if ( createBtn.GetState() == STATE_CLICKED )
{
createBtn.ResetState(); createBtn.ResetState();
if (cntcheats > 0) { if ( cntcheats > 0 )
{
int selectednrs[30]; int selectednrs[30];
int x = 0; int x = 0;
for (int i = 0; i <= cntcheats; i++) { for ( int i = 0; i <= cntcheats; i++ )
{
const char *strCheck = cheatslst.GetName( i ); const char *strCheck = cheatslst.GetName( i );
if (strncmp(strCheck,"ON",2) == 0) { if ( strncmp( strCheck, "ON", 2 ) == 0 )
{
selectednrs[x] = i; selectednrs[x] = i;
x++; x++;
} }
} }
if (x == 0) { if ( x == 0 )
{
WindowPrompt( tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ) ); WindowPrompt( tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ) );
} else { }
else
{
subfoldercreate( Settings.Cheatcodespath ); subfoldercreate( Settings.Cheatcodespath );
string chtpath = Settings.Cheatcodespath; string chtpath = Settings.Cheatcodespath;
string gctfname = chtpath + c.getGameID() + ".gct"; string gctfname = chtpath + c.getGameID() + ".gct";
@ -145,10 +160,12 @@ int CheatMenu(const char * gameID) {
exit = true; exit = true;
break; break;
} }
} else WindowPrompt(tr("Error"),tr("Could not create GCT file"),tr("OK")); }
else WindowPrompt( tr( "Error" ), tr( "Could not create GCT file" ), tr( "OK" ) );
} }
if (backBtn.GetState() == STATE_CLICKED) { if ( backBtn.GetState() == STATE_CLICKED )
{
backBtn.ResetState(); backBtn.ResetState();
exit = true; exit = true;
break; break;

View File

@ -12,11 +12,13 @@
#define ERRORRANGE "Error: CheatNr out of range" #define ERRORRANGE "Error: CheatNr out of range"
GCTCheats::GCTCheats(void) { GCTCheats::GCTCheats( void )
{
iCntCheats = 0; iCntCheats = 0;
} }
GCTCheats::~GCTCheats(void) { GCTCheats::~GCTCheats( void )
{
string sGameID = ""; string sGameID = "";
string sGameTitle = ""; string sGameTitle = "";
@ -25,43 +27,59 @@ GCTCheats::~GCTCheats(void) {
string sCheatComment[MAXCHEATS];*/ string sCheatComment[MAXCHEATS];*/
} }
int GCTCheats::getCnt() { int GCTCheats::getCnt()
{
return iCntCheats; return iCntCheats;
} }
string GCTCheats::getGameName(void) { string GCTCheats::getGameName( void )
{
return sGameTitle; return sGameTitle;
} }
string GCTCheats::getGameID(void) { string GCTCheats::getGameID( void )
{
return sGameID; return sGameID;
} }
string GCTCheats::getCheat(int nr) { string GCTCheats::getCheat( int nr )
if (nr <= (iCntCheats-1)) { {
if ( nr <= ( iCntCheats - 1 ) )
{
return sCheats[nr]; return sCheats[nr];
} else { }
else
{
return ERRORRANGE; return ERRORRANGE;
} }
} }
string GCTCheats::getCheatName(int nr) { string GCTCheats::getCheatName( int nr )
if (nr <= (iCntCheats-1)) { {
if ( nr <= ( iCntCheats - 1 ) )
{
return sCheatName[nr]; return sCheatName[nr];
} else { }
else
{
return ERRORRANGE; return ERRORRANGE;
} }
} }
string GCTCheats::getCheatComment(int nr) { string GCTCheats::getCheatComment( int nr )
if (nr <= (iCntCheats-1)) { {
if ( nr <= ( iCntCheats - 1 ) )
{
return sCheatComment[nr]; return sCheatComment[nr];
} else { }
else
{
return ERRORRANGE; return ERRORRANGE;
} }
} }
int GCTCheats::createGCT(int nr,const char * filename) { int GCTCheats::createGCT( int nr, const char * filename )
{
if ( nr == 0 ) if ( nr == 0 )
return 0; return 0;
@ -83,7 +101,8 @@ int GCTCheats::createGCT(int nr,const char * filename) {
long int li; long int li;
int len = buf.size(); int len = buf.size();
while (x < len) { while ( x < len )
{
string temp = buf.substr( x, 2 ); string temp = buf.substr( x, 2 );
li = strtol( temp.c_str(), NULL, 16 ); li = strtol( temp.c_str(), NULL, 16 );
temp = li; temp = li;
@ -96,7 +115,8 @@ int GCTCheats::createGCT(int nr,const char * filename) {
return 1; return 1;
} }
int GCTCheats::createGCT(const char * chtbuffer,const char * filename) { int GCTCheats::createGCT( const char * chtbuffer, const char * filename )
{
ofstream filestr; ofstream filestr;
filestr.open( filename ); filestr.open( filename );
@ -115,7 +135,8 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
long int li; long int li;
int len = buf.size(); int len = buf.size();
while (x < len) { while ( x < len )
{
string temp = buf.substr( x, 2 ); string temp = buf.substr( x, 2 );
li = strtol( temp.c_str(), NULL, 16 ); li = strtol( temp.c_str(), NULL, 16 );
temp = li; temp = li;
@ -130,7 +151,8 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
return 1; return 1;
} }
int GCTCheats::createGCT(int nr[],int cnt,const char * filename) { int GCTCheats::createGCT( int nr[], int cnt, const char * filename )
{
if ( cnt == 0 ) if ( cnt == 0 )
return 0; return 0;
@ -148,14 +170,16 @@ int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
filestr.write( header, sizeof( header ) ); filestr.write( header, sizeof( header ) );
int c = 0; int c = 0;
while (c != cnt) { while ( c != cnt )
{
int actnr = nr[c]; int actnr = nr[c];
string buf = getCheat( actnr ); string buf = getCheat( actnr );
long int li; long int li;
int len = buf.size(); int len = buf.size();
int x = 0; int x = 0;
while (x < len) { while ( x < len )
{
string temp = buf.substr( x, 2 ); string temp = buf.substr( x, 2 );
li = strtol( temp.c_str(), NULL, 16 ); li = strtol( temp.c_str(), NULL, 16 );
temp = li; temp = li;
@ -170,7 +194,8 @@ int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
return 1; return 1;
} }
int GCTCheats::openTxtfile(const char * filename) { int GCTCheats::openTxtfile( const char * filename )
{
ifstream filestr; ifstream filestr;
int i = 0; int i = 0;
string str; string str;
@ -196,7 +221,8 @@ int GCTCheats::openTxtfile(const char * filename) {
if ( !sGameTitle[sGameTitle.length() - 1] == '\r' ) if ( !sGameTitle[sGameTitle.length() - 1] == '\r' )
filestr.seekg( 0, ios_base::beg ); filestr.seekg( 0, ios_base::beg );
while (!filestr.eof()) { while ( !filestr.eof() )
{
getline( filestr, sCheatName[i] ); // '\n' delimiter by default getline( filestr, sCheatName[i] ); // '\n' delimiter by default
if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' ) if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' )
sCheatName[i].erase( sCheatName[i].length() - 1 ); sCheatName[i].erase( sCheatName[i].length() - 1 );
@ -204,31 +230,38 @@ int GCTCheats::openTxtfile(const char * filename) {
string cheatdata; string cheatdata;
bool emptyline = false; bool emptyline = false;
do { do
{
getline( filestr, str ); getline( filestr, str );
if ( str[str.length() - 1] == '\r' ) if ( str[str.length() - 1] == '\r' )
str.erase( str.length() - 1 ); str.erase( str.length() - 1 );
if (str == "" || str[0] == '\r' || str[0] == '\n') { if ( str == "" || str[0] == '\r' || str[0] == '\n' )
{
emptyline = true; emptyline = true;
break; break;
} }
if (IsCode(str)) { if ( IsCode( str ) )
{
// remove any garbage (comment) after code // remove any garbage (comment) after code
while (str.size() > 17) { while ( str.size() > 17 )
{
str.erase( str.length() - 1 ); str.erase( str.length() - 1 );
} }
cheatdata.append( str ); cheatdata.append( str );
size_t found = cheatdata.find( ' ' ); size_t found = cheatdata.find( ' ' );
cheatdata.replace( found, 1, "" ); cheatdata.replace( found, 1, "" );
} else { }
else
{
//printf("%i",str.size()); //printf("%i",str.size());
sCheatComment[i] = str; sCheatComment[i] = str;
} }
if ( filestr.eof() ) break; if ( filestr.eof() ) break;
} while (!emptyline); }
while ( !emptyline );
sCheats[i] = cheatdata; sCheats[i] = cheatdata;
i++; i++;
@ -239,14 +272,17 @@ int GCTCheats::openTxtfile(const char * filename) {
return 1; return 1;
} }
bool GCTCheats::IsCode(const std::string& str) { bool GCTCheats::IsCode( const std::string& str )
if (str[8] == ' ' && str.size() >= 17) { {
if ( str[8] == ' ' && str.size() >= 17 )
{
// accept strings longer than 17 in case there is a comment on the same line as the code // accept strings longer than 17 in case there is a comment on the same line as the code
char part1[9]; char part1[9];
char part2[9]; char part2[9];
snprintf( part1, sizeof( part1 ), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7] ); snprintf( part1, sizeof( part1 ), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], 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( 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)) { if ( ( strtok( part1, "0123456789ABCDEFabcdef" ) == NULL ) && ( strtok( part2, "0123456789ABCDEFabcdef" ) == NULL ) )
{
return true; return true;
} }
} }

View File

@ -14,7 +14,8 @@
using namespace std; using namespace std;
//!Handles Ocarina TXT Cheatfiles //!Handles Ocarina TXT Cheatfiles
class GCTCheats { class GCTCheats
{
private: private:
string sGameID; string sGameID;
string sGameTitle; string sGameTitle;

View File

@ -44,7 +44,8 @@ sec_t fat_wbfs_sec = 0;
int fs_ntfs_mount = 0; int fs_ntfs_mount = 0;
sec_t fs_ntfs_sec = 0; sec_t fs_ntfs_sec = 0;
int USBDevice_Init() { int USBDevice_Init()
{
#ifdef DEBUG_FAT #ifdef DEBUG_FAT
gprintf( "\nUSBDevice_Init()" ); gprintf( "\nUSBDevice_Init()" );
#endif #endif
@ -55,7 +56,8 @@ int USBDevice_Init() {
//try first mount with cIOS //try first mount with cIOS
// if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) { // if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
// //try now mount with libogc // //try now mount with libogc
if (!fatMount("USB", &__io_usbstorage2, 0, CACHE, SECTORS)) { if ( !fatMount( "USB", &__io_usbstorage2, 0, CACHE, SECTORS ) )
{
#ifdef DEBUG_FAT #ifdef DEBUG_FAT
gprintf( ":-1" ); gprintf( ":-1" );
#endif #endif
@ -71,7 +73,8 @@ int USBDevice_Init() {
return 0; return 0;
} }
void USBDevice_deInit() { void USBDevice_deInit()
{
#ifdef DEBUG_FAT #ifdef DEBUG_FAT
gprintf( "\nUSBDevice_deInit()" ); gprintf( "\nUSBDevice_deInit()" );
#endif #endif
@ -82,7 +85,8 @@ void USBDevice_deInit() {
fat_usb_sec = 0; fat_usb_sec = 0;
} }
int WBFSDevice_Init(u32 sector) { int WBFSDevice_Init( u32 sector )
{
//closing all open Files write back the cache and then shutdown em! //closing all open Files write back the cache and then shutdown em!
fatUnmount( "WBFS:/" ); fatUnmount( "WBFS:/" );
//right now mounts first FAT-partition //right now mounts first FAT-partition
@ -90,21 +94,24 @@ int WBFSDevice_Init(u32 sector) {
//try first mount with cIOS //try first mount with cIOS
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) { // if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
//try now mount with libogc //try now mount with libogc
if (!fatMount("WBFS", &__io_usbstorage2, 0, CACHE, SECTORS)) { if ( !fatMount( "WBFS", &__io_usbstorage2, 0, CACHE, SECTORS ) )
{
return -1; return -1;
} }
// } // }
fat_wbfs_mount = 1; fat_wbfs_mount = 1;
fat_wbfs_sec = _FAT_startSector; fat_wbfs_sec = _FAT_startSector;
if (sector && fat_wbfs_sec != sector) { if ( sector && fat_wbfs_sec != sector )
{
// This is an error situation...actually, but is ignored in Config loader also // This is an error situation...actually, but is ignored in Config loader also
// Should ask Oggzee about it... // Should ask Oggzee about it...
} }
return 0; return 0;
} }
void WBFSDevice_deInit() { void WBFSDevice_deInit()
{
//closing all open Files write back the cache and then shutdown em! //closing all open Files write back the cache and then shutdown em!
fatUnmount( "WBFS:/" ); fatUnmount( "WBFS:/" );
@ -112,21 +119,24 @@ void WBFSDevice_deInit() {
fat_wbfs_sec = 0; fat_wbfs_sec = 0;
} }
int isInserted(const char *path) { int isInserted( const char *path )
{
if ( !strncmp( path, "USB:", 4 ) ) if ( !strncmp( path, "USB:", 4 ) )
return 1; return 1;
return __io_sdhc.isInserted() || __io_wiisd.isInserted(); return __io_sdhc.isInserted() || __io_wiisd.isInserted();
} }
int SDCard_Init() { int SDCard_Init()
{
#ifdef DEBUG_FAT #ifdef DEBUG_FAT
gprintf( "\nSDCard_Init()" ); gprintf( "\nSDCard_Init()" );
#endif #endif
//closing all open Files write back the cache and then shutdown em! //closing all open Files write back the cache and then shutdown em!
fatUnmount( "SD:/" ); fatUnmount( "SD:/" );
//right now mounts first FAT-partition //right now mounts first FAT-partition
if (fatMount("SD", &__io_wiisd, 0, CACHE, SECTORS)) { if ( fatMount( "SD", &__io_wiisd, 0, CACHE, SECTORS ) )
{
fat_sd_mount = MOUNT_SD; fat_sd_mount = MOUNT_SD;
fat_sd_sec = _FAT_startSector; fat_sd_sec = _FAT_startSector;
#ifdef DEBUG_FAT #ifdef DEBUG_FAT
@ -134,7 +144,8 @@ int SDCard_Init() {
#endif #endif
return 1; return 1;
} }
else if (fatMount("SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE)) { else if ( fatMount( "SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE ) )
{
fat_sd_mount = MOUNT_SDHC; fat_sd_mount = MOUNT_SDHC;
fat_sd_sec = _FAT_startSector; fat_sd_sec = _FAT_startSector;
#ifdef DEBUG_FAT #ifdef DEBUG_FAT
@ -148,7 +159,8 @@ int SDCard_Init() {
return -1; return -1;
} }
void SDCard_deInit() { void SDCard_deInit()
{
#ifdef DEBUG_FAT #ifdef DEBUG_FAT
gprintf( "\nSDCard_deInit()" ); gprintf( "\nSDCard_deInit()" );
#endif #endif
@ -178,28 +190,37 @@ s32 MountNTFS(u32 sector)
setlocale( LC_CTYPE, "C-UTF-8" ); setlocale( LC_CTYPE, "C-UTF-8" );
setlocale( LC_MESSAGES, "C-UTF-8" ); setlocale( LC_MESSAGES, "C-UTF-8" );
if (wbfsDev == WBFS_DEVICE_USB) { if ( wbfsDev == WBFS_DEVICE_USB )
{
/* Initialize WBFS interface */ /* Initialize WBFS interface */
// if (!__io_wiiums.startup()) { // if (!__io_wiiums.startup()) {
ret = __io_usbstorage2.startup(); ret = __io_usbstorage2.startup();
if (!ret) { if ( !ret )
{
return -1; return -1;
} }
// } // }
/* Mount device */ /* Mount device */
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) { // if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER ); ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
if (!ret) { if ( !ret )
{
return -2; return -2;
} }
// } // }
} else if (wbfsDev == WBFS_DEVICE_SDHC) { }
if (sdhc_mode_sd == 0) { else if ( wbfsDev == WBFS_DEVICE_SDHC )
{
if ( sdhc_mode_sd == 0 )
{
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER ); ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
} else { }
else
{
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER ); ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
} }
if (!ret) { if ( !ret )
{
return -5; return -5;
} }
} }

View File

@ -2,7 +2,8 @@
#define _FATMOUNTER_H_ #define _FATMOUNTER_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
extern int fat_sd_mount; extern int fat_sd_mount;

View File

@ -4,7 +4,8 @@
#define _GECKO_H_ #define _GECKO_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
char ascii( char s ); char ascii( char s );

View File

@ -48,7 +48,8 @@ u8 boothomebrew = 0;
/**************************************************************************** /****************************************************************************
* roundup Function * roundup Function
***************************************************************************/ ***************************************************************************/
int roundup(float number) { int roundup( float number )
{
if ( number == ( int ) number ) if ( number == ( int ) number )
return ( int ) number; return ( int ) number;
else else
@ -58,7 +59,8 @@ int roundup(float number) {
/**************************************************************************** /****************************************************************************
* MenuHomebrewBrowse * MenuHomebrewBrowse
***************************************************************************/ ***************************************************************************/
int MenuHomebrewBrowse() { int MenuHomebrewBrowse()
{
int menu = MENU_NONE; int menu = MENU_NONE;
int choice = 0; int choice = 0;
@ -66,12 +68,14 @@ int MenuHomebrewBrowse() {
u32 filecount = HomebrewFiles.GetFilecount(); u32 filecount = HomebrewFiles.GetFilecount();
if (!filecount) { if ( !filecount )
{
WindowPrompt( tr( "No .dol or .elf files found." ), 0, tr( "OK" ) ); WindowPrompt( tr( "No .dol or .elf files found." ), 0, tr( "OK" ) );
return MENU_DISCLIST; return MENU_DISCLIST;
} }
enum { enum
{
FADE, FADE,
LEFT, LEFT,
RIGHT RIGHT
@ -141,7 +145,8 @@ int MenuHomebrewBrowse() {
GuiImageData *IconData[4]; GuiImageData *IconData[4];
GuiImage *IconImg[4]; GuiImage *IconImg[4];
for (int i = 0; i < 4; i++) { for ( int i = 0; i < 4; i++ )
{
IconData[i] = NULL; IconData[i] = NULL;
IconImg[i] = NULL; IconImg[i] = NULL;
} }
@ -150,7 +155,8 @@ int MenuHomebrewBrowse() {
GuiText backBtnTxt( tr( "Back" ) , 22, THEME.prompttext ); GuiText backBtnTxt( tr( "Back" ) , 22, THEME.prompttext );
backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 ); backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
GuiImage backBtnImg( &btnOutline ); GuiImage backBtnImg( &btnOutline );
if (Settings.wsprompt == yes) { if ( Settings.wsprompt == yes )
{
backBtnTxt.SetWidescreen( CFG.widescreen ); backBtnTxt.SetWidescreen( CFG.widescreen );
backBtnImg.SetWidescreen( CFG.widescreen ); backBtnImg.SetWidescreen( CFG.widescreen );
} }
@ -297,7 +303,8 @@ int MenuHomebrewBrowse() {
MainButton4.SetTrigger( &trigA ); MainButton4.SetTrigger( &trigA );
GuiImage wifiImg( &wifiImgData ); GuiImage wifiImg( &wifiImgData );
if (Settings.wsprompt == yes) { if ( Settings.wsprompt == yes )
{
wifiImg.SetWidescreen( CFG.widescreen ); wifiImg.SetWidescreen( CFG.widescreen );
} }
GuiButton wifiBtn( wifiImg.GetWidth(), wifiImg.GetHeight() ); GuiButton wifiBtn( wifiImg.GetWidth(), wifiImg.GetHeight() );
@ -332,7 +339,8 @@ int MenuHomebrewBrowse() {
const int pages = roundup( filecount / 4.0f ); const int pages = roundup( filecount / 4.0f );
bool wifi_btn_loaded = false; bool wifi_btn_loaded = false;
while (menu == MENU_NONE) { //set pageToDisplay to 0 to quit while ( menu == MENU_NONE ) //set pageToDisplay to 0 to quit
{
VIDEO_WaitVSync (); VIDEO_WaitVSync ();
menu = MENU_NONE; menu = MENU_NONE;
@ -345,13 +353,16 @@ int MenuHomebrewBrowse() {
MainButton3.StopEffect(); MainButton3.StopEffect();
MainButton4.StopEffect(); MainButton4.StopEffect();
if (slidedirection == RIGHT) { if ( slidedirection == RIGHT )
{
MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 ); MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 ); MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
MainButton3.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 ); 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) { }
else if ( slidedirection == LEFT )
{
MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 ); MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 ); MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 ); MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
@ -364,20 +375,25 @@ int MenuHomebrewBrowse() {
mainWindow->RemoveAll(); mainWindow->RemoveAll();
/** Set new icons **/ /** Set new icons **/
for (int i = 0; i < 4; i++) { for ( int i = 0; i < 4; i++ )
if (IconData[i] != NULL) { {
if ( IconData[i] != NULL )
{
delete IconData[i]; delete IconData[i];
IconData[i] = NULL; IconData[i] = NULL;
} }
if (IconImg[i] != NULL) { if ( IconImg[i] != NULL )
{
delete IconImg[i]; delete IconImg[i];
IconImg[i] = NULL; IconImg[i] = NULL;
} }
if (fileoffset+i < (int) filecount) { if ( fileoffset + i < ( int ) filecount )
{
char iconpath[200]; char iconpath[200];
snprintf( iconpath, sizeof( iconpath ), "%sicon.png", HomebrewFiles.GetFilepath( fileoffset + i ) ); snprintf( iconpath, sizeof( iconpath ), "%sicon.png", HomebrewFiles.GetFilepath( fileoffset + i ) );
IconData[i] = new GuiImageData( iconpath, 0 ); IconData[i] = new GuiImageData( iconpath, 0 );
if (IconData[i]->GetImage()) { if ( IconData[i]->GetImage() )
{
IconImg[i] = new GuiImage( IconData[i] ); IconImg[i] = new GuiImage( IconData[i] );
IconImg[i]->SetAlignment( ALIGN_LEFT, ALIGN_MIDDLE ); IconImg[i]->SetAlignment( ALIGN_LEFT, ALIGN_MIDDLE );
IconImg[i]->SetPosition( 12, 0 ); IconImg[i]->SetPosition( 12, 0 );
@ -414,20 +430,25 @@ int MenuHomebrewBrowse() {
w.Append( &GoRightBtn ); w.Append( &GoRightBtn );
w.Append( &GoLeftBtn ); w.Append( &GoLeftBtn );
if (pageToDisplay == pages) { if ( pageToDisplay == pages )
{
int buttonsleft = filecount - ( pages - 1 ) * 4; int buttonsleft = filecount - ( pages - 1 ) * 4;
char * shortpath = NULL; char * shortpath = NULL;
char temp[200]; char temp[200];
if (buttonsleft > 0) { if ( buttonsleft > 0 )
{
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) );
if (XMLInfo[0].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[0].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() );
MainButton1Txt.SetText( MainButtonText ); MainButton1Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
MainButton1DescTxt.SetText( MainButtonText ); MainButton1DescTxt.SetText( MainButtonText );
MainButton1DescOverTxt.SetText( MainButtonText ); MainButton1DescOverTxt.SetText( MainButtonText );
} else { }
else
{
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) ); snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
shortpath = strrchr( temp, '/' ); shortpath = strrchr( temp, '/' );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
@ -439,15 +460,19 @@ int MenuHomebrewBrowse() {
} }
w.Append( &MainButton1 ); w.Append( &MainButton1 );
} }
if (buttonsleft > 1) { if ( buttonsleft > 1 )
{
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
if (XMLInfo[1].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[1].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() );
MainButton2Txt.SetText( MainButtonText ); MainButton2Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
MainButton2DescTxt.SetText( MainButtonText ); MainButton2DescTxt.SetText( MainButtonText );
MainButton2DescOverTxt.SetText( MainButtonText ); MainButton2DescOverTxt.SetText( MainButtonText );
} else { }
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, '/' ); 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 ) );
@ -459,15 +484,19 @@ int MenuHomebrewBrowse() {
} }
w.Append( &MainButton2 ); w.Append( &MainButton2 );
} }
if (buttonsleft > 2) { if ( buttonsleft > 2 )
{
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
MainButton3Txt.SetText( MainButtonText ); MainButton3Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
MainButton3DescTxt.SetText( MainButtonText ); MainButton3DescTxt.SetText( MainButtonText );
MainButton3DescOverTxt.SetText( MainButtonText ); MainButton3DescOverTxt.SetText( MainButtonText );
} else { }
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, '/' ); 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 ) );
@ -479,15 +508,19 @@ int MenuHomebrewBrowse() {
} }
w.Append( &MainButton3 ); w.Append( &MainButton3 );
} }
if (buttonsleft > 3) { if ( buttonsleft > 3 )
{
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
MainButton4Txt.SetText( MainButtonText ); MainButton4Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
MainButton4DescTxt.SetText( MainButtonText ); MainButton4DescTxt.SetText( MainButtonText );
MainButton4DescOverTxt.SetText( MainButtonText ); MainButton4DescOverTxt.SetText( MainButtonText );
} else { }
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, '/' ); 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 ) );
@ -499,18 +532,23 @@ int MenuHomebrewBrowse() {
} }
w.Append( &MainButton4 ); w.Append( &MainButton4 );
} }
} else { }
else
{
char temp[200]; char temp[200];
char *shortpath = NULL; char *shortpath = NULL;
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) );
if (XMLInfo[0].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[0].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() );
MainButton1Txt.SetText( MainButtonText ); MainButton1Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
MainButton1DescTxt.SetText( MainButtonText ); MainButton1DescTxt.SetText( MainButtonText );
MainButton1DescOverTxt.SetText( MainButtonText ); MainButton1DescOverTxt.SetText( MainButtonText );
} else { }
else
{
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) ); snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
shortpath = strrchr( temp, '/' ); shortpath = strrchr( temp, '/' );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
@ -524,13 +562,16 @@ int MenuHomebrewBrowse() {
w.Append( &MainButton1 ); w.Append( &MainButton1 );
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
if (XMLInfo[1].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[1].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() );
MainButton2Txt.SetText( MainButtonText ); MainButton2Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
MainButton2DescTxt.SetText( MainButtonText ); MainButton2DescTxt.SetText( MainButtonText );
MainButton2DescOverTxt.SetText( MainButtonText ); MainButton2DescOverTxt.SetText( MainButtonText );
} else { }
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, '/' ); 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 ) );
@ -544,13 +585,16 @@ int MenuHomebrewBrowse() {
w.Append( &MainButton2 ); w.Append( &MainButton2 );
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
MainButton3Txt.SetText( MainButtonText ); MainButton3Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
MainButton3DescTxt.SetText( MainButtonText ); MainButton3DescTxt.SetText( MainButtonText );
MainButton3DescOverTxt.SetText( MainButtonText ); MainButton3DescOverTxt.SetText( MainButtonText );
} else { }
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, '/' ); 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 ) );
@ -563,13 +607,16 @@ int MenuHomebrewBrowse() {
w.Append( &MainButton3 ); w.Append( &MainButton3 );
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) ); snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) { if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
{
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
MainButton4Txt.SetText( MainButtonText ); MainButton4Txt.SetText( MainButtonText );
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() ); snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
MainButton4DescTxt.SetText( MainButtonText ); MainButton4DescTxt.SetText( MainButtonText );
MainButton4DescOverTxt.SetText( MainButtonText ); MainButton4DescOverTxt.SetText( MainButtonText );
} else { }
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, '/' ); 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 ) );
@ -593,17 +640,22 @@ int MenuHomebrewBrowse() {
MainButton3.SetEffectGrow(); MainButton3.SetEffectGrow();
MainButton4.SetEffectGrow(); MainButton4.SetEffectGrow();
if (slidedirection == FADE) { if ( slidedirection == FADE )
{
MainButton1.SetEffect( EFFECT_FADE, 20 ); MainButton1.SetEffect( EFFECT_FADE, 20 );
MainButton2.SetEffect( EFFECT_FADE, 20 ); MainButton2.SetEffect( EFFECT_FADE, 20 );
MainButton3.SetEffect( EFFECT_FADE, 20 ); MainButton3.SetEffect( EFFECT_FADE, 20 );
MainButton4.SetEffect( EFFECT_FADE, 20 ); MainButton4.SetEffect( EFFECT_FADE, 20 );
} else if (slidedirection == LEFT) { }
else if ( slidedirection == LEFT )
{
MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 ); MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 ); MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
MainButton3.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 ); MainButton3.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
MainButton4.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 ); MainButton4.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
} else if (slidedirection == RIGHT) { }
else if ( slidedirection == RIGHT )
{
MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 ); MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 ); MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 ); MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
@ -616,10 +668,12 @@ int MenuHomebrewBrowse() {
while ( MainButton1.GetEffect() > 0 ) usleep( 50 ); while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
while (!changed) { while ( !changed )
{
VIDEO_WaitVSync (); VIDEO_WaitVSync ();
if (MainButton1.GetState() == STATE_CLICKED) { if ( MainButton1.GetState() == STATE_CLICKED )
{
char temp[200]; char temp[200];
char iconpath[200]; char iconpath[200];
char metapath[200]; char metapath[200];
@ -639,14 +693,17 @@ int MenuHomebrewBrowse() {
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) ); 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) { if ( choice == 1 )
{
boothomebrew = 1; boothomebrew = 1;
menu = MENU_EXIT; 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; break;
} }
MainButton1.ResetState(); MainButton1.ResetState();
} else if (MainButton2.GetState() == STATE_CLICKED) { }
else if ( MainButton2.GetState() == STATE_CLICKED )
{
char temp[200]; char temp[200];
char iconpath[200]; char iconpath[200];
char metapath[200]; char metapath[200];
@ -666,14 +723,17 @@ int MenuHomebrewBrowse() {
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) ); 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) { if ( choice == 1 )
{
boothomebrew = 1; boothomebrew = 1;
menu = MENU_EXIT; 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; break;
} }
MainButton2.ResetState(); MainButton2.ResetState();
} else if (MainButton3.GetState() == STATE_CLICKED) { }
else if ( MainButton3.GetState() == STATE_CLICKED )
{
char temp[200]; char temp[200];
char iconpath[200]; char iconpath[200];
char metapath[200]; char metapath[200];
@ -693,14 +753,17 @@ int MenuHomebrewBrowse() {
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) ); 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) { if ( choice == 1 )
{
boothomebrew = 1; boothomebrew = 1;
menu = MENU_EXIT; 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; break;
} }
MainButton3.ResetState(); MainButton3.ResetState();
} else if (MainButton4.GetState() == STATE_CLICKED) { }
else if ( MainButton4.GetState() == STATE_CLICKED )
{
char temp[200]; char temp[200];
char iconpath[200]; char iconpath[200];
char metapath[200]; char metapath[200];
@ -720,7 +783,8 @@ int MenuHomebrewBrowse() {
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) ); 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) { if ( choice == 1 )
{
boothomebrew = 1; boothomebrew = 1;
menu = MENU_EXIT; 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 ) );
@ -734,12 +798,14 @@ int MenuHomebrewBrowse() {
else if ( reset == 1 ) else if ( reset == 1 )
Sys_Reboot(); Sys_Reboot();
else if (backBtn.GetState() == STATE_CLICKED) { else if ( backBtn.GetState() == STATE_CLICKED )
{
menu = MENU_DISCLIST; menu = MENU_DISCLIST;
changed = true; changed = true;
} }
else if (GoLeftBtn.GetState() == STATE_CLICKED) { else if ( GoLeftBtn.GetState() == STATE_CLICKED )
{
pageToDisplay--; pageToDisplay--;
/** Change direction of the flying buttons **/ /** Change direction of the flying buttons **/
if ( pageToDisplay < 1 ) if ( pageToDisplay < 1 )
@ -749,7 +815,8 @@ int MenuHomebrewBrowse() {
GoLeftBtn.ResetState(); GoLeftBtn.ResetState();
} }
else if (GoRightBtn.GetState() == STATE_CLICKED) { else if ( GoRightBtn.GetState() == STATE_CLICKED )
{
pageToDisplay++; pageToDisplay++;
/** Change direction of the flying buttons **/ /** Change direction of the flying buttons **/
if ( pageToDisplay > pages ) if ( pageToDisplay > pages )
@ -759,28 +826,36 @@ int MenuHomebrewBrowse() {
GoRightBtn.ResetState(); GoRightBtn.ResetState();
} }
else if (wifiBtn.GetState() == STATE_CLICKED) { else if ( wifiBtn.GetState() == STATE_CLICKED )
{
ResumeNetworkWait(); ResumeNetworkWait();
wifiBtn.ResetState(); wifiBtn.ResetState();
} }
else if (homo.GetState() == STATE_CLICKED) { else if ( homo.GetState() == STATE_CLICKED )
{
cfg_save_global(); cfg_save_global();
bgMusic->Pause(); bgMusic->Pause();
choice = WindowExitPrompt(); choice = WindowExitPrompt();
bgMusic->Resume(); bgMusic->Resume();
if (choice == 3) { if ( choice == 3 )
{
Sys_LoadMenu(); // Back to System Menu Sys_LoadMenu(); // Back to System Menu
} else if (choice == 2) { }
else if ( choice == 2 )
{
Sys_BackToLoader(); Sys_BackToLoader();
} else { }
else
{
homo.ResetState(); homo.ResetState();
} }
} }
else if (infilesize > 0) { else if ( infilesize > 0 )
{
char filesizetxt[50]; char filesizetxt[50];
char temp[50]; char temp[50];
@ -793,14 +868,18 @@ int MenuHomebrewBrowse() {
int choice = WindowPrompt( filesizetxt, temp, tr( "OK" ), tr( "Cancel" ) ); int choice = WindowPrompt( filesizetxt, temp, tr( "OK" ), tr( "Cancel" ) );
if (choice == 1) { if ( choice == 1 )
{
int res = AllocHomebrewMemory( infilesize ); int res = AllocHomebrewMemory( infilesize );
if (res < 0) { if ( res < 0 )
{
CloseConnection(); CloseConnection();
WindowPrompt( tr( "Not enough free memory." ), 0, tr( "OK" ) ); WindowPrompt( tr( "Not enough free memory." ), 0, tr( "OK" ) );
} else { }
else
{
u32 read = 0; u32 read = 0;
u8 *temp = NULL; u8 *temp = NULL;
int len = NETWORKBLOCKSIZE; int len = NETWORKBLOCKSIZE;
@ -808,7 +887,8 @@ int MenuHomebrewBrowse() {
bool error = false; bool error = false;
u8 *ptr = temp; u8 *ptr = temp;
while (read < infilesize) { while ( read < infilesize )
{
ShowProgress( tr( "Receiving file from:" ), GetIncommingIP(), NULL, read, infilesize, true ); ShowProgress( tr( "Receiving file from:" ), GetIncommingIP(), NULL, read, infilesize, true );
@ -819,12 +899,14 @@ int MenuHomebrewBrowse() {
int result = network_read( ptr, len ); int result = network_read( ptr, len );
if (result < 0) { if ( result < 0 )
{
WindowPrompt( tr( "Error while transfering data." ), 0, tr( "OK" ) ); WindowPrompt( tr( "Error while transfering data." ), 0, tr( "OK" ) );
error = true; error = true;
break; break;
} }
if (!result) { if ( !result )
{
break; break;
} }
@ -834,15 +916,18 @@ int MenuHomebrewBrowse() {
} }
char filename[101]; char filename[101];
if (!error) { if ( !error )
{
network_read( ( u8* ) &filename, 100 ); network_read( ( u8* ) &filename, 100 );
// Do we need to unzip this thing? // Do we need to unzip this thing?
if (wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4) { if ( wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4 )
{
// We need to unzip... // We need to unzip...
if (temp[0] == 'P' && temp[1] == 'K' && temp[2] == 0x03 && temp[3] == 0x04) { if ( temp[0] == 'P' && temp[1] == 'K' && temp[2] == 0x03 && temp[3] == 0x04 )
{
// It's a zip file, unzip to the apps directory // It's a zip file, unzip to the apps directory
// Zip archive, ask for permission to install the zip // Zip archive, ask for permission to install the zip
@ -857,9 +942,12 @@ int MenuHomebrewBrowse() {
// Now unzip the zip file... // Now unzip the zip file...
unzFile uf = unzOpen( zippath ); unzFile uf = unzOpen( zippath );
if (uf==NULL) { if ( uf == NULL )
{
error = true; error = true;
} else { }
else
{
extractZip( uf, 0, 1, 0, Settings.homebrewapps_path ); extractZip( uf, 0, 1, 0, Settings.homebrewapps_path );
unzCloseCurrentFile( uf ); unzCloseCurrentFile( uf );
@ -869,10 +957,14 @@ int MenuHomebrewBrowse() {
menu = MENU_HOMEBREWBROWSE; menu = MENU_HOMEBREWBROWSE;
break; break;
} }
} else { }
else
{
error = true; error = true;
} }
} else if (uncfilesize != 0) { // if uncfilesize == 0, it's not compressed }
else if ( uncfilesize != 0 ) // if uncfilesize == 0, it's not compressed
{
// It's compressed, uncompress // It's compressed, uncompress
u8 *unc = ( u8 * ) malloc( uncfilesize ); u8 *unc = ( u8 * ) malloc( uncfilesize );
uLongf f = uncfilesize; uLongf f = uncfilesize;
@ -885,7 +977,8 @@ int MenuHomebrewBrowse() {
} }
} }
if (!error && strstr(filename,".zip") == NULL) { if ( !error && strstr( filename, ".zip" ) == NULL )
{
innetbuffer = temp; innetbuffer = temp;
} }
@ -893,21 +986,29 @@ int MenuHomebrewBrowse() {
ProgressStop(); ProgressStop();
if (error || read != infilesize) { if ( error || read != infilesize )
{
WindowPrompt( tr( "Error:" ), tr( "No data could be read." ), tr( "OK" ) ); WindowPrompt( tr( "Error:" ), tr( "No data could be read." ), tr( "OK" ) );
FreeHomebrewBuffer(); FreeHomebrewBuffer();
} else { }
else
{
if ( strstr( filename, ".dol" ) || strstr( filename, ".DOL" ) if ( strstr( filename, ".dol" ) || strstr( filename, ".DOL" )
|| strstr(filename,".elf") || strstr(filename,".ELF")) { || strstr( filename, ".elf" ) || strstr( filename, ".ELF" ) )
{
boothomebrew = 2; boothomebrew = 2;
AddBootArgument( filename ); AddBootArgument( filename );
menu = MENU_EXIT; menu = MENU_EXIT;
CloseConnection(); CloseConnection();
break; break;
} else if (strstr(filename,".zip")) { }
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(); CloseConnection();
} else { }
else
{
FreeHomebrewBuffer(); FreeHomebrewBuffer();
WindowPrompt( tr( "ERROR:" ), tr( "Not a DOL/ELF file." ), tr( "OK" ) ); WindowPrompt( tr( "ERROR:" ), tr( "Not a DOL/ELF file." ), tr( "OK" ) );
} }
@ -918,7 +1019,8 @@ int MenuHomebrewBrowse() {
ResumeNetworkWait(); ResumeNetworkWait();
} }
else if (channelBtn.GetState() == STATE_CLICKED) { else if ( channelBtn.GetState() == STATE_CLICKED )
{
w.SetState( STATE_DISABLED ); w.SetState( STATE_DISABLED );
//10001 are the channels that are installed as channels, not including shop channel/mii channel etc //10001 are the channels that are installed as channels, not including shop channel/mii channel etc
TitleBrowser(); TitleBrowser();
@ -929,8 +1031,10 @@ int MenuHomebrewBrowse() {
} }
if (IsNetworkInit()) { if ( IsNetworkInit() )
if (!wifi_btn_loaded) { {
if ( !wifi_btn_loaded )
{
wifiBtn.SetAlpha( 255 ); wifiBtn.SetAlpha( 255 );
titleTT = new GuiTooltip( GetNetworkIP() ); titleTT = new GuiTooltip( GetNetworkIP() );
@ -947,12 +1051,15 @@ int MenuHomebrewBrowse() {
HaltGui(); HaltGui();
for (int i = 0; i < 4; i++) { for ( int i = 0; i < 4; i++ )
if (IconData[i] != NULL) { {
if ( IconData[i] != NULL )
{
delete IconData[i]; delete IconData[i];
IconData[i] = NULL; IconData[i] = NULL;
} }
if (IconImg[i] != NULL) { if ( IconImg[i] != NULL )
{
delete IconImg[i]; delete IconImg[i];
IconImg[i] = NULL; IconImg[i] = NULL;
} }

View File

@ -9,11 +9,13 @@
#include "HomebrewFiles.h" #include "HomebrewFiles.h"
HomebrewFiles::HomebrewFiles(const char * path) { HomebrewFiles::HomebrewFiles( const char * path )
{
filecount = 0; filecount = 0;
FileInfo = ( FileInfos * ) malloc( sizeof( FileInfos ) ); FileInfo = ( FileInfos * ) malloc( sizeof( FileInfos ) );
if (!FileInfo) { if ( !FileInfo )
{
return; return;
} }
@ -23,42 +25,54 @@ HomebrewFiles::HomebrewFiles(const char * path) {
this->SortList(); this->SortList();
} }
HomebrewFiles::~HomebrewFiles() { HomebrewFiles::~HomebrewFiles()
if (FileInfo) { {
if ( FileInfo )
{
free( FileInfo ); free( FileInfo );
FileInfo = NULL; FileInfo = NULL;
} }
} }
bool HomebrewFiles::LoadPath(const char * folderpath) { bool HomebrewFiles::LoadPath( const char * folderpath )
{
struct stat st; struct stat st;
DIR_ITER *dir = NULL; DIR_ITER *dir = NULL;
char filename[1024]; char filename[1024];
dir = diropen( folderpath ); dir = diropen( folderpath );
if (dir == NULL) { if ( dir == NULL )
{
return false; return false;
} }
while (dirnext(dir,filename,&st) == 0) { while ( dirnext( dir, filename, &st ) == 0 )
if ((st.st_mode & S_IFDIR) != 0) { {
if (strcmp(filename,".") != 0 && strcmp(filename,"..") != 0) { if ( ( st.st_mode & S_IFDIR ) != 0 )
{
if ( strcmp( filename, "." ) != 0 && strcmp( filename, ".." ) != 0 )
{
char currentname[200]; char currentname[200];
snprintf( currentname, sizeof( currentname ), "%s%s/", folderpath, filename ); snprintf( currentname, sizeof( currentname ), "%s%s/", folderpath, filename );
this->LoadPath( currentname ); this->LoadPath( currentname );
} }
} else { }
else
{
char temp[5]; char temp[5];
for (int i = 0; i < 5; i++) { for ( int i = 0; i < 5; i++ )
{
temp[i] = filename[strlen( filename )-4+i]; temp[i] = filename[strlen( filename )-4+i];
} }
if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 ) if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 )
&& filecount < MAXHOMEBREWS && filename[0]!='.') { && filecount < MAXHOMEBREWS && filename[0] != '.' )
{
FileInfo = ( FileInfos * ) realloc( FileInfo, ( filecount + 1 ) * sizeof( FileInfos ) ); FileInfo = ( FileInfos * ) realloc( FileInfo, ( filecount + 1 ) * sizeof( FileInfos ) );
if (!FileInfo) { if ( !FileInfo )
{
free( FileInfo ); free( FileInfo );
FileInfo = NULL; FileInfo = NULL;
filecount = 0; filecount = 0;
@ -80,37 +94,43 @@ bool HomebrewFiles::LoadPath(const char * folderpath) {
return true; return true;
} }
char * HomebrewFiles::GetFilename(int ind) { char * HomebrewFiles::GetFilename( int ind )
{
if ( ind > filecount ) if ( ind > filecount )
return NULL; return NULL;
else else
return FileInfo[ind].FileName; return FileInfo[ind].FileName;
} }
char * HomebrewFiles::GetFilepath(int ind) { char * HomebrewFiles::GetFilepath( int ind )
{
if ( ind > filecount ) if ( ind > filecount )
return NULL; return NULL;
else else
return FileInfo[ind].FilePath; return FileInfo[ind].FilePath;
} }
unsigned int HomebrewFiles::GetFilesize(int ind) { unsigned int HomebrewFiles::GetFilesize( int ind )
{
if ( ind > filecount || !filecount || !FileInfo ) if ( ind > filecount || !filecount || !FileInfo )
return NULL; return NULL;
else else
return FileInfo[ind].FileSize; return FileInfo[ind].FileSize;
} }
int HomebrewFiles::GetFilecount() { int HomebrewFiles::GetFilecount()
{
return filecount; return filecount;
} }
static int ListCompare(const void *a, const void *b) { static int ListCompare( const void *a, const void *b )
{
FileInfos *ab = ( FileInfos* ) a; FileInfos *ab = ( FileInfos* ) a;
FileInfos *bb = ( FileInfos* ) b; FileInfos *bb = ( FileInfos* ) b;
return stricmp( ( char * ) ab->FilePath, ( char * ) bb->FilePath ); return stricmp( ( char * ) ab->FilePath, ( char * ) bb->FilePath );
} }
void HomebrewFiles::SortList() { void HomebrewFiles::SortList()
{
qsort( FileInfo, filecount, sizeof( FileInfos ), ListCompare ); qsort( FileInfo, filecount, sizeof( FileInfos ), ListCompare );
} }

View File

@ -7,13 +7,15 @@
#define MAXHOMEBREWS 500 #define MAXHOMEBREWS 500
typedef struct { typedef struct
{
char FileName[100]; char FileName[100];
char FilePath[150]; char FilePath[150];
unsigned int FileSize; unsigned int FileSize;
} FileInfos; } FileInfos;
class HomebrewFiles { class HomebrewFiles
{
public: public:
//!Constructor //!Constructor
//!\param path Path where to check for homebrew files //!\param path Path where to check for homebrew files

View File

@ -8,7 +8,8 @@
#include "dolloader.h" #include "dolloader.h"
typedef struct _dolheader { typedef struct _dolheader
{
u32 text_pos[7]; u32 text_pos[7];
u32 data_pos[11]; u32 data_pos[11];
u32 text_start[7]; u32 text_start[7];
@ -20,19 +21,23 @@ typedef struct _dolheader {
u32 entry_point; u32 entry_point;
} dolheader; } dolheader;
u32 load_dol(const void *dolstart, struct __argv *argv) { u32 load_dol( const void *dolstart, struct __argv *argv )
{
u32 i; u32 i;
dolheader *dolfile; dolheader *dolfile;
if (dolstart) { if ( dolstart )
{
dolfile = ( dolheader * ) dolstart; dolfile = ( dolheader * ) dolstart;
for (i = 0; i < 7; i++) { for ( i = 0; i < 7; i++ )
{
if ( ( !dolfile->text_size[i] ) || ( dolfile->text_start[i] < 0x100 ) ) continue; if ( ( !dolfile->text_size[i] ) || ( dolfile->text_start[i] < 0x100 ) ) continue;
ICInvalidateRange ( ( void * ) dolfile->text_start[i], dolfile->text_size[i] ); ICInvalidateRange ( ( void * ) dolfile->text_start[i], dolfile->text_size[i] );
memcpy( ( void * ) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i] ); memcpy( ( void * ) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i] );
} }
for (i = 0; i < 11; i++) { for ( i = 0; i < 11; i++ )
{
if ( ( !dolfile->data_size[i] ) || ( dolfile->data_start[i] < 0x100 ) ) continue; if ( ( !dolfile->data_size[i] ) || ( dolfile->data_start[i] < 0x100 ) ) continue;
memcpy( ( void * ) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i] ); memcpy( ( void * ) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i] );
DCFlushRangeNoSync ( ( void * ) dolfile->data_start[i], dolfile->data_size[i] ); DCFlushRangeNoSync ( ( void * ) dolfile->data_start[i], dolfile->data_size[i] );
@ -41,7 +46,8 @@ u32 load_dol(const void *dolstart, struct __argv *argv) {
memset ( ( void * ) dolfile->bss_start, 0, dolfile->bss_size ); memset ( ( void * ) dolfile->bss_start, 0, dolfile->bss_size );
DCFlushRange( ( void * ) dolfile->bss_start, dolfile->bss_size ); DCFlushRange( ( void * ) dolfile->bss_start, dolfile->bss_size );
if (argv && argv->argvMagic == ARGV_MAGIC) { if ( argv && argv->argvMagic == ARGV_MAGIC )
{
void *new_argv = ( void * )( dolfile->entry_point + 8 ); void *new_argv = ( void * )( dolfile->entry_point + 8 );
memcpy( new_argv, argv, sizeof( *argv ) ); memcpy( new_argv, argv, sizeof( *argv ) );
DCFlushRange( new_argv, sizeof( *argv ) ); DCFlushRange( new_argv, sizeof( *argv ) );

View File

@ -2,7 +2,8 @@
#define _DOLLOADER_H_ #define _DOLLOADER_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
extern void __exception_closeall(); extern void __exception_closeall();

View File

@ -77,8 +77,10 @@ void SetupPads()
* ShutoffRumble * ShutoffRumble
***************************************************************************/ ***************************************************************************/
void ShutoffRumble() { void ShutoffRumble()
for (int i=0;i<4;i++) { {
for ( int i = 0; i < 4; i++ )
{
WPAD_Rumble( i, 0 ); WPAD_Rumble( i, 0 );
rumbleCount[i] = 0; rumbleCount[i] = 0;
} }
@ -88,14 +90,20 @@ void ShutoffRumble() {
* DoRumble * DoRumble
***************************************************************************/ ***************************************************************************/
void DoRumble(int i) { void DoRumble( int i )
if (rumbleRequest[i] && rumbleCount[i] < 3) { {
if ( rumbleRequest[i] && rumbleCount[i] < 3 )
{
WPAD_Rumble( i, 1 ); // rumble on WPAD_Rumble( i, 1 ); // rumble on
rumbleCount[i]++; rumbleCount[i]++;
} else if (rumbleRequest[i]) { }
else if ( rumbleRequest[i] )
{
rumbleCount[i] = 20; rumbleCount[i] = 20;
rumbleRequest[i] = 0; rumbleRequest[i] = 0;
} else { }
else
{
if ( rumbleCount[i] ) if ( rumbleCount[i] )
rumbleCount[i]--; rumbleCount[i]--;
WPAD_Rumble( i, 0 ); // rumble off WPAD_Rumble( i, 0 ); // rumble off
@ -108,25 +116,31 @@ void DoRumble(int i) {
* Get X/Y value from Wii Joystick (classic, nunchuk) input * Get X/Y value from Wii Joystick (classic, nunchuk) input
***************************************************************************/ ***************************************************************************/
s8 WPAD_Stick(u8 chan, u8 right, int axis) { s8 WPAD_Stick( u8 chan, u8 right, int axis )
{
float mag = 0.0; float mag = 0.0;
float ang = 0.0; float ang = 0.0;
WPADData *data = WPAD_Data( chan ); WPADData *data = WPAD_Data( chan );
switch (data->exp.type) { switch ( data->exp.type )
{
case WPAD_EXP_NUNCHUK: case WPAD_EXP_NUNCHUK:
case WPAD_EXP_GUITARHERO3: case WPAD_EXP_GUITARHERO3:
if (right == 0) { if ( right == 0 )
{
mag = data->exp.nunchuk.js.mag; mag = data->exp.nunchuk.js.mag;
ang = data->exp.nunchuk.js.ang; ang = data->exp.nunchuk.js.ang;
} }
break; break;
case WPAD_EXP_CLASSIC: case WPAD_EXP_CLASSIC:
if (right == 0) { if ( right == 0 )
{
mag = data->exp.classic.ljs.mag; mag = data->exp.classic.ljs.mag;
ang = data->exp.classic.ljs.ang; ang = data->exp.classic.ljs.ang;
} else { }
else
{
mag = data->exp.classic.rjs.mag; mag = data->exp.classic.rjs.mag;
ang = data->exp.classic.rjs.ang; ang = data->exp.classic.rjs.ang;
} }

View File

@ -13,7 +13,8 @@
#include "network/networkops.h" #include "network/networkops.h"
#include "network/http.h" #include "network/http.h"
int updateLanguageFiles() { int updateLanguageFiles()
{
char languageFiles[50][MAXLANGUAGEFILES]; char languageFiles[50][MAXLANGUAGEFILES];
//get all the files in the language path //get all the files in the language path
@ -23,10 +24,12 @@ int updateLanguageFiles() {
if ( !countfiles ) return -2; if ( !countfiles ) return -2;
//now from the files we got, get only the .lang files //now from the files we got, get only the .lang files
for (int cnt = 0; cnt < countfiles; cnt++) { for ( int cnt = 0; cnt < countfiles; cnt++ )
{
char filename[64]; char filename[64];
strlcpy( filename, GetFileName( cnt ), sizeof( filename ) ); strlcpy( filename, GetFileName( cnt ), sizeof( filename ) );
if (strcasestr(filename,".lang")) { if ( strcasestr( filename, ".lang" ) )
{
strcpy( languageFiles[cnt], filename ); strcpy( languageFiles[cnt], filename );
} }
} }
@ -36,9 +39,11 @@ int updateLanguageFiles() {
//we assume that the network will already be init by another function //we assume that the network will already be init by another function
// ( that has gui eletents in it because this one doesn't) // ( that has gui eletents in it because this one doesn't)
int done = 0, j = 0; int done = 0, j = 0;
if (IsNetworkInit()) { if ( IsNetworkInit() )
{
//build the URL, save path, and download each file and save it //build the URL, save path, and download each file and save it
while (j<countfiles) { while ( j < countfiles )
{
char savepath[150]; char savepath[150];
char codeurl[200]; char codeurl[200];
snprintf( codeurl, sizeof( codeurl ), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s", languageFiles[j] ); snprintf( codeurl, sizeof( codeurl ), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s", languageFiles[j] );
@ -46,10 +51,12 @@ int updateLanguageFiles() {
struct block file = downloadfile( codeurl ); struct block file = downloadfile( codeurl );
if (file.data != NULL) { if ( file.data != NULL )
{
FILE * pfile; FILE * pfile;
pfile = fopen( savepath, "wb" ); pfile = fopen( savepath, "wb" );
if(pfile != NULL) { if ( pfile != NULL )
{
fwrite( file.data, 1, file.size, pfile ); fwrite( file.data, 1, file.size, pfile );
fclose( pfile ); fclose( pfile );
free( file.data ); free( file.data );

View File

@ -4,7 +4,8 @@
#include <gctypes.h> #include <gctypes.h>
#include "gettext.h" #include "gettext.h"
typedef struct _MSG { typedef struct _MSG
{
u32 id; u32 id;
char* msgstr; char* msgstr;
struct _MSG *next; struct _MSG *next;
@ -18,17 +19,20 @@ static MSG *baseMSG=0;
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
1986, 1987 Bell Telephone Laboratories, Inc.] */ 1986, 1987 Bell Telephone Laboratories, Inc.] */
static inline u32 static inline u32
hash_string (const char *str_param) { hash_string ( const char *str_param )
{
u32 hval, g; u32 hval, g;
const char *str = str_param; const char *str = str_param;
/* Compute the hash value for the given string. */ /* Compute the hash value for the given string. */
hval = 0; hval = 0;
while (*str != '\0') { while ( *str != '\0' )
{
hval <<= 4; hval <<= 4;
hval += ( u8 ) * str++; hval += ( u8 ) * str++;
g = hval & ( ( u32 ) 0xf << ( HASHWORDBITS - 4 ) ); g = hval & ( ( u32 ) 0xf << ( HASHWORDBITS - 4 ) );
if (g != 0) { if ( g != 0 )
{
hval ^= g >> ( HASHWORDBITS - 8 ); hval ^= g >> ( HASHWORDBITS - 8 );
hval ^= g; hval ^= g;
} }
@ -38,7 +42,8 @@ hash_string (const char *str_param) {
/* Expand some escape sequences found in the argument string. */ /* Expand some escape sequences found in the argument string. */
static char * static char *
expand_escape (const char *str) { expand_escape ( const char *str )
{
char *retval, *rp; char *retval, *rp;
const char *cp = str; const char *cp = str;
@ -50,10 +55,12 @@ expand_escape (const char *str) {
*rp++ = *cp++; *rp++ = *cp++;
if ( cp[0] == '\0' ) if ( cp[0] == '\0' )
goto terminate; goto terminate;
do { do
{
/* Here cp[0] == '\\'. */ /* Here cp[0] == '\\'. */
switch (*++cp) { switch ( *++cp )
{
case '\"': /* " */ case '\"': /* " */
*rp++ = '\"'; *rp++ = '\"';
++cp; ++cp;
@ -97,14 +104,17 @@ expand_escape (const char *str) {
case '4': case '4':
case '5': case '5':
case '6': case '6':
case '7': { case '7':
{
int ch = *cp++ - '0'; int ch = *cp++ - '0';
if (*cp >= '0' && *cp <= '7') { if ( *cp >= '0' && *cp <= '7' )
{
ch *= 8; ch *= 8;
ch += *cp++ - '0'; ch += *cp++ - '0';
if (*cp >= '0' && *cp <= '7') { if ( *cp >= '0' && *cp <= '7' )
{
ch *= 8; ch *= 8;
ch += *cp++ - '0'; ch += *cp++ - '0';
} }
@ -119,7 +129,8 @@ expand_escape (const char *str) {
while ( cp[0] != '\0' && cp[0] != '\\' ) while ( cp[0] != '\0' && cp[0] != '\\' )
*rp++ = *cp++; *rp++ = *cp++;
} while (cp[0] != '\0'); }
while ( cp[0] != '\0' );
/* Terminate string. */ /* Terminate string. */
terminate: terminate:
@ -127,27 +138,33 @@ terminate:
return retval; return retval;
} }
static MSG *findMSG(u32 id) { static MSG *findMSG( u32 id )
{
MSG *msg; MSG *msg;
for (msg=baseMSG; msg; msg=msg->next) { for ( msg = baseMSG; msg; msg = msg->next )
{
if ( msg->id == id ) if ( msg->id == id )
return msg; return msg;
} }
return NULL; return NULL;
} }
static MSG *setMSG(const char *msgid, const char *msgstr) { static MSG *setMSG( const char *msgid, const char *msgstr )
{
u32 id = hash_string( msgid ); u32 id = hash_string( msgid );
MSG *msg = findMSG( id ); MSG *msg = findMSG( id );
if (!msg) { if ( !msg )
{
msg = ( MSG * )malloc( sizeof( MSG ) ); msg = ( MSG * )malloc( sizeof( MSG ) );
msg->id = id; msg->id = id;
msg->msgstr = NULL; msg->msgstr = NULL;
msg->next = baseMSG; msg->next = baseMSG;
baseMSG = msg; baseMSG = msg;
} }
if (msg) { if ( msg )
if (msgstr) { {
if ( msgstr )
{
if ( msg->msgstr ) free( msg->msgstr ); if ( msg->msgstr ) free( msg->msgstr );
//msg->msgstr = strdup(msgstr); //msg->msgstr = strdup(msgstr);
msg->msgstr = expand_escape( msgstr ); msg->msgstr = expand_escape( msgstr );
@ -156,8 +173,10 @@ static MSG *setMSG(const char *msgid, const char *msgstr) {
} }
return NULL; return NULL;
} }
void gettextCleanUp(void) { void gettextCleanUp( void )
while (baseMSG) { {
while ( baseMSG )
{
MSG *nextMsg = baseMSG->next; MSG *nextMsg = baseMSG->next;
free( baseMSG->msgstr ); free( baseMSG->msgstr );
free( baseMSG ); free( baseMSG );
@ -166,7 +185,8 @@ void gettextCleanUp(void) {
} }
bool gettextLoadLanguage(const char* langFile) { bool gettextLoadLanguage( const char* langFile )
{
FILE *f; FILE *f;
char line[200]; char line[200];
char *lastID = NULL; char *lastID = NULL;
@ -176,23 +196,29 @@ bool gettextLoadLanguage(const char* langFile) {
if ( !f ) if ( !f )
return false; return false;
while (fgets(line, sizeof(line), f)) { while ( fgets( line, sizeof( line ), f ) )
{
// lines starting with # are comments // lines starting with # are comments
if ( line[0] == '#' ) if ( line[0] == '#' )
continue; continue;
else if (strncmp(line, "msgid \"", 7) == 0) { else if ( strncmp( line, "msgid \"", 7 ) == 0 )
{
char *msgid, *end; char *msgid, *end;
if (lastID) { if ( lastID )
{
free( lastID ); free( lastID );
lastID = NULL; lastID = NULL;
} }
msgid = &line[7]; msgid = &line[7];
end = strrchr( msgid, '"' ); end = strrchr( msgid, '"' );
if (end && end-msgid>1) { if ( end && end - msgid > 1 )
{
*end = 0; *end = 0;
lastID = strdup( msgid ); lastID = strdup( msgid );
} }
} else if (strncmp(line, "msgstr \"", 8) == 0) { }
else if ( strncmp( line, "msgstr \"", 8 ) == 0 )
{
char *msgstr, *end; char *msgstr, *end;
if ( lastID == NULL ) if ( lastID == NULL )
@ -200,7 +226,8 @@ bool gettextLoadLanguage(const char* langFile) {
msgstr = &line[8]; msgstr = &line[8];
end = strrchr( msgstr, '"' ); end = strrchr( msgstr, '"' );
if (end && end-msgstr>1) { if ( end && end - msgstr > 1 )
{
*end = 0; *end = 0;
setMSG( lastID, msgstr ); setMSG( lastID, msgstr );
} }
@ -213,7 +240,8 @@ bool gettextLoadLanguage(const char* langFile) {
fclose( f ); fclose( f );
return true; return true;
} }
const char *gettext(const char *msgid) { const char *gettext( const char *msgid )
{
MSG *msg = findMSG( hash_string( msgid ) ); MSG *msg = findMSG( hash_string( msgid ) );
if ( msg && msg->msgstr ) return msg->msgstr; if ( msg && msg->msgstr ) return msg->msgstr;
return msgid; return msgid;

View File

@ -2,7 +2,8 @@
#define _GETTEXT_H_ #define _GETTEXT_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif

View File

@ -34,20 +34,24 @@
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
Functions to deal with little endian values stored in uint8_t arrays Functions to deal with little endian values stored in uint8_t arrays
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) { static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
{
return ( item[offset] | ( item[offset + 1] << 8 ) ); return ( item[offset] | ( item[offset + 1] << 8 ) );
} }
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) { static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
{
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) ); return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
} }
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) { static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
{
item[offset] = ( uint8_t ) value; item[offset] = ( uint8_t ) value;
item[offset + 1] = ( uint8_t )( value >> 8 ); item[offset + 1] = ( uint8_t )( value >> 8 );
} }
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) { static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
{
item[offset] = ( uint8_t ) value; item[offset] = ( uint8_t ) value;
item[offset + 1] = ( uint8_t )( value >> 8 ); item[offset + 1] = ( uint8_t )( value >> 8 );
item[offset + 2] = ( uint8_t )( value >> 16 ); item[offset + 2] = ( uint8_t )( value >> 16 );

View File

@ -42,7 +42,8 @@
#define PAGE_SECTORS 64 #define PAGE_SECTORS 64
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS) #define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
typedef struct { typedef struct
{
sec_t sector; sec_t sector;
unsigned int count; unsigned int count;
unsigned int last_access; unsigned int last_access;
@ -50,7 +51,8 @@ typedef struct {
uint8_t* cache; uint8_t* cache;
} CACHE_ENTRY; } CACHE_ENTRY;
typedef struct { typedef struct
{
const DISC_INTERFACE* disc; const DISC_INTERFACE* disc;
sec_t endOfPartition; sec_t endOfPartition;
unsigned int numberOfPages; unsigned int numberOfPages;
@ -99,14 +101,16 @@ bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void*
/* /*
Read a full sector from the cache Read a full sector from the cache
*/ */
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) { static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
{
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ ); return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
} }
/* /*
Write a full sector to the cache Write a full sector to the cache
*/ */
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) { static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
{
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ ); return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
} }

File diff suppressed because it is too large Load Diff

View File

@ -59,13 +59,15 @@
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE; typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
typedef struct { typedef struct
{
uint32_t cluster; uint32_t cluster;
sec_t sector; sec_t sector;
int32_t offset; int32_t offset;
} DIR_ENTRY_POSITION; } DIR_ENTRY_POSITION;
typedef struct { typedef struct
{
uint8_t entryData[DIR_ENTRY_DATA_SIZE]; uint8_t entryData[DIR_ENTRY_DATA_SIZE];
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
@ -73,7 +75,8 @@ typedef struct {
} DIR_ENTRY; } DIR_ENTRY;
// Directory entry offsets // Directory entry offsets
enum DIR_ENTRY_offset { enum DIR_ENTRY_offset
{
DIR_ENTRY_name = 0x00, DIR_ENTRY_name = 0x00,
DIR_ENTRY_extension = 0x08, DIR_ENTRY_extension = 0x08,
DIR_ENTRY_attributes = 0x0B, DIR_ENTRY_attributes = 0x0B,
@ -92,15 +95,18 @@ enum DIR_ENTRY_offset {
/* /*
Returns true if the file specified by entry is a directory Returns true if the file specified by entry is a directory
*/ */
static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) { static inline bool _FAT_directory_isDirectory ( DIR_ENTRY* entry )
{
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR ) != 0 ); return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR ) != 0 );
} }
static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) { static inline bool _FAT_directory_isWritable ( DIR_ENTRY* entry )
{
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO ) == 0 ); return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO ) == 0 );
} }
static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) { static inline bool _FAT_directory_isDot ( DIR_ENTRY* entry )
{
return ( ( entry->filename[0] == '.' ) && ( ( entry->filename[1] == '\0' ) || return ( ( entry->filename[0] == '.' ) && ( ( entry->filename[1] == '\0' ) ||
( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) ); ( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) );
} }

View File

@ -35,7 +35,8 @@
A list of all default devices to try at startup, A list of all default devices to try at startup,
terminated by a {NULL,NULL} entry. terminated by a {NULL,NULL} entry.
*/ */
typedef struct { typedef struct
{
const char* name; const char* name;
const DISC_INTERFACE* ( *getInterface )( void ); const DISC_INTERFACE* ( *getInterface )( void );
} INTERFACE_ID; } INTERFACE_ID;
@ -45,7 +46,8 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
Check if a disc is inserted Check if a disc is inserted
Return true if a disc is inserted and ready, false otherwise Return true if a disc is inserted and ready, false otherwise
*/ */
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
{
return disc->isInserted(); return disc->isInserted();
} }
@ -56,7 +58,8 @@ else it is at least 1
sector is 0 or greater sector is 0 or greater
buffer is a pointer to the memory to fill buffer is a pointer to the memory to fill
*/ */
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) { static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
{
return disc->readSectors ( sector, numSectors, buffer ); return disc->readSectors ( sector, numSectors, buffer );
} }
@ -67,21 +70,24 @@ else it is at least 1
sector is 0 or greater sector is 0 or greater
buffer is a pointer to the memory to read from buffer is a pointer to the memory to read from
*/ */
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) { static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
{
return disc->writeSectors ( sector, numSectors, buffer ); return disc->writeSectors ( sector, numSectors, buffer );
} }
/* /*
Reset the card back to a ready state Reset the card back to a ready state
*/ */
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
{
return disc->clearStatus(); return disc->clearStatus();
} }
/* /*
Initialise the disc to a state ready for data reading or writing Initialise the disc to a state ready for data reading or writing
*/ */
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
{
return disc->startup(); return disc->startup();
} }
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
Put the disc in a state ready for power down. Put the disc in a state ready for power down.
Complete any pending writes and disable the disc if necessary Complete any pending writes and disable the disc if necessary
*/ */
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
{
return disc->shutdown(); return disc->shutdown();
} }
/* /*
Return a 32 bit value unique to each type of interface Return a 32 bit value unique to each type of interface
*/ */
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) { static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
{
return disc->ioType; return disc->ioType;
} }
/* /*
Return a 32 bit value that specifies the capabilities of the disc Return a 32 bit value that specifies the capabilities of the disc
*/ */
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) { static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
{
return disc->features; return disc->features;
} }

View File

@ -43,21 +43,26 @@ The list is terminated by a NULL/NULL entry.
#include "usbloader/usbstorage2.h" #include "usbloader/usbstorage2.h"
#include <sdcard/gcsd.h> #include <sdcard/gcsd.h>
static const DISC_INTERFACE* get_io_wiisd (void) { static const DISC_INTERFACE* get_io_wiisd ( void )
{
return &__io_wiisd; return &__io_wiisd;
} }
static const DISC_INTERFACE* get_io_usbstorage (void) { static const DISC_INTERFACE* get_io_usbstorage ( void )
{
return &__io_usbstorage2; return &__io_usbstorage2;
} }
static const DISC_INTERFACE* get_io_gcsda (void) { static const DISC_INTERFACE* get_io_gcsda ( void )
{
return &__io_gcsda; return &__io_gcsda;
} }
static const DISC_INTERFACE* get_io_gcsdb (void) { static const DISC_INTERFACE* get_io_gcsdb ( void )
{
return &__io_gcsdb; return &__io_gcsdb;
} }
const INTERFACE_ID _FAT_disc_interfaces[] = { const INTERFACE_ID _FAT_disc_interfaces[] =
{
{"sd", get_io_wiisd}, {"sd", get_io_wiisd},
{"usb", get_io_usbstorage}, {"usb", get_io_usbstorage},
{"carda", get_io_gcsda}, {"carda", get_io_gcsda},

View File

@ -35,7 +35,8 @@
A list of all default devices to try at startup, A list of all default devices to try at startup,
terminated by a {NULL,NULL} entry. terminated by a {NULL,NULL} entry.
*/ */
typedef struct { typedef struct
{
const char* name; const char* name;
const DISC_INTERFACE* ( *getInterface )( void ); const DISC_INTERFACE* ( *getInterface )( void );
} INTERFACE_ID; } INTERFACE_ID;
@ -45,7 +46,8 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
Check if a disc is inserted Check if a disc is inserted
Return true if a disc is inserted and ready, false otherwise Return true if a disc is inserted and ready, false otherwise
*/ */
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
{
return disc->isInserted(); return disc->isInserted();
} }
@ -56,7 +58,8 @@ else it is at least 1
sector is 0 or greater sector is 0 or greater
buffer is a pointer to the memory to fill buffer is a pointer to the memory to fill
*/ */
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) { static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
{
return disc->readSectors ( sector, numSectors, buffer ); return disc->readSectors ( sector, numSectors, buffer );
} }
@ -67,21 +70,24 @@ else it is at least 1
sector is 0 or greater sector is 0 or greater
buffer is a pointer to the memory to read from buffer is a pointer to the memory to read from
*/ */
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) { static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
{
return disc->writeSectors ( sector, numSectors, buffer ); return disc->writeSectors ( sector, numSectors, buffer );
} }
/* /*
Reset the card back to a ready state Reset the card back to a ready state
*/ */
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
{
return disc->clearStatus(); return disc->clearStatus();
} }
/* /*
Initialise the disc to a state ready for data reading or writing Initialise the disc to a state ready for data reading or writing
*/ */
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
{
return disc->startup(); return disc->startup();
} }
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
Put the disc in a state ready for power down. Put the disc in a state ready for power down.
Complete any pending writes and disable the disc if necessary Complete any pending writes and disable the disc if necessary
*/ */
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) { static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
{
return disc->shutdown(); return disc->shutdown();
} }
/* /*
Return a 32 bit value unique to each type of interface Return a 32 bit value unique to each type of interface
*/ */
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) { static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
{
return disc->ioType; return disc->ioType;
} }
/* /*
Return a 32 bit value that specifies the capabilities of the disc Return a 32 bit value that specifies the capabilities of the disc
*/ */
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) { static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
{
return disc->features; return disc->features;
} }

View File

@ -31,7 +31,8 @@
#define _LIBFAT_H #define _LIBFAT_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
#include <stdint.h> #include <stdint.h>

View File

@ -46,21 +46,25 @@
#define CACHE_FREE UINT_MAX #define CACHE_FREE UINT_MAX
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition) { CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition )
{
CACHE* cache; CACHE* cache;
unsigned int i; unsigned int i;
CACHE_ENTRY* cacheEntries; CACHE_ENTRY* cacheEntries;
if (numberOfPages < 2) { if ( numberOfPages < 2 )
{
numberOfPages = 2; numberOfPages = 2;
} }
if (sectorsPerPage < 8) { if ( sectorsPerPage < 8 )
{
sectorsPerPage = 8; sectorsPerPage = 8;
} }
cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) ); cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) );
if (cache == NULL) { if ( cache == NULL )
{
return NULL; return NULL;
} }
@ -71,12 +75,14 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsP
cacheEntries = ( CACHE_ENTRY* ) _FAT_mem_allocate ( sizeof( CACHE_ENTRY ) * numberOfPages ); cacheEntries = ( CACHE_ENTRY* ) _FAT_mem_allocate ( sizeof( CACHE_ENTRY ) * numberOfPages );
if (cacheEntries == NULL) { if ( cacheEntries == NULL )
{
_FAT_mem_free ( cache ); _FAT_mem_free ( cache );
return NULL; return NULL;
} }
for (i = 0; i < numberOfPages; i++) { for ( i = 0; i < numberOfPages; i++ )
{
cacheEntries[i].sector = CACHE_FREE; cacheEntries[i].sector = CACHE_FREE;
cacheEntries[i].count = 0; cacheEntries[i].count = 0;
cacheEntries[i].last_access = 0; cacheEntries[i].last_access = 0;
@ -89,13 +95,15 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsP
return cache; return cache;
} }
void _FAT_cache_destructor (CACHE* cache) { void _FAT_cache_destructor ( CACHE* cache )
{
unsigned int i; unsigned int i;
// Clear out cache before destroying it // Clear out cache before destroying it
_FAT_cache_flush( cache ); _FAT_cache_flush( cache );
// Free memory in reverse allocation order // Free memory in reverse allocation order
for (i = 0; i < cache->numberOfPages; i++) { for ( i = 0; i < cache->numberOfPages; i++ )
{
_FAT_mem_free ( cache->cacheEntries[i].cache ); _FAT_mem_free ( cache->cacheEntries[i].cache );
} }
_FAT_mem_free ( cache->cacheEntries ); _FAT_mem_free ( cache->cacheEntries );
@ -105,7 +113,8 @@ void _FAT_cache_destructor (CACHE* cache) {
static u32 accessCounter = 0; static u32 accessCounter = 0;
static u32 accessTime(){ static u32 accessTime()
{
accessCounter++; accessCounter++;
return accessCounter; return accessCounter;
} }
@ -122,20 +131,24 @@ static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector)
unsigned int oldUsed = 0; unsigned int oldUsed = 0;
unsigned int oldAccess = UINT_MAX; unsigned int oldAccess = UINT_MAX;
for(i=0;i<numberOfPages;i++) { for ( i = 0; i < numberOfPages; i++ )
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) { {
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
{
cacheEntries[i].last_access = accessTime(); cacheEntries[i].last_access = accessTime();
return &( cacheEntries[i] ); return &( cacheEntries[i] );
} }
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) { if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
{
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true; if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
oldUsed = i; oldUsed = i;
oldAccess = cacheEntries[i].last_access; oldAccess = cacheEntries[i].last_access;
} }
} }
if(foundFree==false && cacheEntries[oldUsed].dirty==true) { if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
{
if ( !_FAT_disc_writeSectors( cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL; if ( !_FAT_disc_writeSectors( cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
cacheEntries[oldUsed].dirty = false; cacheEntries[oldUsed].dirty = false;
} }
@ -160,7 +173,8 @@ bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buf
CACHE_ENTRY *entry; CACHE_ENTRY *entry;
uint8_t *dest = buffer; uint8_t *dest = buffer;
while(numSectors>0) { while ( numSectors > 0 )
{
entry = _FAT_cache_getPage( cache, sector ); entry = _FAT_cache_getPage( cache, sector );
if ( entry == NULL ) return false; if ( entry == NULL ) return false;
@ -197,11 +211,13 @@ bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, uns
return true; return true;
} }
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) { bool _FAT_cache_readLittleEndianValue ( CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
{
uint8_t buf[4]; uint8_t buf[4];
if ( !_FAT_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false; if ( !_FAT_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
switch(num_bytes) { switch ( num_bytes )
{
case 1: *value = buf[0]; break; case 1: *value = buf[0]; break;
case 2: *value = u8array_to_u16( buf, 0 ); break; case 2: *value = u8array_to_u16( buf, 0 ); break;
case 4: *value = u8array_to_u32( buf, 0 ); break; case 4: *value = u8array_to_u32( buf, 0 ); break;
@ -230,10 +246,12 @@ bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sect
return true; return true;
} }
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) { bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
{
uint8_t buf[4] = {0, 0, 0, 0}; uint8_t buf[4] = {0, 0, 0, 0};
switch(size) { switch ( size )
{
case 1: buf[0] = value; break; case 1: buf[0] = value; break;
case 2: u16_to_u8array( buf, 0, value ); break; case 2: u16_to_u8array( buf, 0, value ); break;
case 4: u32_to_u8array( buf, 0, value ); break; case 4: u32_to_u8array( buf, 0, value ); break;
@ -265,7 +283,8 @@ bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t
} }
static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count) { static CACHE_ENTRY* _FAT_cache_findPage( CACHE *cache, sec_t sector, sec_t count )
{
unsigned int i; unsigned int i;
CACHE_ENTRY* cacheEntries = cache->cacheEntries; CACHE_ENTRY* cacheEntries = cache->cacheEntries;
@ -273,16 +292,22 @@ static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count)
CACHE_ENTRY *entry = NULL; CACHE_ENTRY *entry = NULL;
sec_t lowest = UINT_MAX; sec_t lowest = UINT_MAX;
for(i=0;i<numberOfPages;i++) { for ( i = 0; i < numberOfPages; i++ )
if (cacheEntries[i].sector != CACHE_FREE) { {
if ( cacheEntries[i].sector != CACHE_FREE )
{
bool intersect; bool intersect;
if (sector > cacheEntries[i].sector) { if ( sector > cacheEntries[i].sector )
{
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count; intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
} else { }
else
{
intersect = cacheEntries[i].sector - sector < count; intersect = cacheEntries[i].sector - sector < count;
} }
if ( intersect && (cacheEntries[i].sector < lowest)) { if ( intersect && ( cacheEntries[i].sector < lowest ) )
{
lowest = cacheEntries[i].sector; lowest = cacheEntries[i].sector;
entry = &cacheEntries[i]; entry = &cacheEntries[i];
} }
@ -303,9 +328,11 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
{ {
entry = _FAT_cache_findPage( cache, sector, numSectors ); entry = _FAT_cache_findPage( cache, sector, numSectors );
if(entry!=NULL) { if ( entry != NULL )
{
if ( entry->sector > sector) { if ( entry->sector > sector )
{
secs_to_write = entry->sector - sector; secs_to_write = entry->sector - sector;
@ -328,7 +355,9 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
entry->dirty = true; entry->dirty = true;
} else { }
else
{
_FAT_disc_writeSectors( cache->disc, sector, numSectors, src ); _FAT_disc_writeSectors( cache->disc, sector, numSectors, src );
numSectors = 0; numSectors = 0;
} }
@ -339,12 +368,16 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
/* /*
Flushes all dirty pages to disc, clearing the dirty flag. Flushes all dirty pages to disc, clearing the dirty flag.
*/ */
bool _FAT_cache_flush (CACHE* cache) { bool _FAT_cache_flush ( CACHE* cache )
{
unsigned int i; unsigned int i;
for (i = 0; i < cache->numberOfPages; i++) { for ( i = 0; i < cache->numberOfPages; i++ )
if (cache->cacheEntries[i].dirty) { {
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) { if ( cache->cacheEntries[i].dirty )
{
if ( !_FAT_disc_writeSectors ( cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
{
return false; return false;
} }
} }
@ -354,10 +387,12 @@ bool _FAT_cache_flush (CACHE* cache) {
return true; return true;
} }
void _FAT_cache_invalidate (CACHE* cache) { void _FAT_cache_invalidate ( CACHE* cache )
{
unsigned int i; unsigned int i;
_FAT_cache_flush( cache ); _FAT_cache_flush( cache );
for (i = 0; i < cache->numberOfPages; i++) { for ( i = 0; i < cache->numberOfPages; i++ )
{
cache->cacheEntries[i].sector = CACHE_FREE; cache->cacheEntries[i].sector = CACHE_FREE;
cache->cacheEntries[i].last_access = 0; cache->cacheEntries[i].last_access = 0;
cache->cacheEntries[i].count = 0; cache->cacheEntries[i].count = 0;

View File

@ -42,7 +42,8 @@
#define PAGE_SECTORS 64 #define PAGE_SECTORS 64
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS) #define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
typedef struct { typedef struct
{
sec_t sector; sec_t sector;
unsigned int count; unsigned int count;
unsigned int last_access; unsigned int last_access;
@ -50,7 +51,8 @@ typedef struct {
uint8_t* cache; uint8_t* cache;
} CACHE_ENTRY; } CACHE_ENTRY;
typedef struct { typedef struct
{
const DISC_INTERFACE* disc; const DISC_INTERFACE* disc;
sec_t endOfPartition; sec_t endOfPartition;
unsigned int numberOfPages; unsigned int numberOfPages;
@ -99,14 +101,16 @@ bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void*
/* /*
Read a full sector from the cache Read a full sector from the cache
*/ */
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) { static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
{
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ ); return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
} }
/* /*
Write a full sector to the cache Write a full sector to the cache
*/ */
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) { static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
{
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ ); return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
} }

View File

@ -45,22 +45,26 @@
#include "lock.h" #include "lock.h"
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) { int _FAT_stat_r ( struct _reent *r, const char *path, struct stat *st )
{
PARTITION* partition = NULL; PARTITION* partition = NULL;
DIR_ENTRY dirEntry; DIR_ENTRY dirEntry;
// Get the partition this file is on // Get the partition this file is on
partition = _FAT_partition_getPartitionFromPath ( path ); partition = _FAT_partition_getPartitionFromPath ( path );
if (partition == NULL) { if ( partition == NULL )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
// Move the path pointer to the start of the actual path // Move the path pointer to the start of the actual path
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
path = strchr ( path, ':' ) + 1; path = strchr ( path, ':' ) + 1;
} }
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -68,7 +72,8 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
_FAT_lock( &partition->lock ); _FAT_lock( &partition->lock );
// Search for the file on the disc // Search for the file on the disc
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) { if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
@ -81,12 +86,14 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
return 0; return 0;
} }
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink) { int _FAT_link_r ( struct _reent *r, const char *existing, const char *newLink )
{
r->_errno = ENOTSUP; r->_errno = ENOTSUP;
return -1; return -1;
} }
int _FAT_unlink_r (struct _reent *r, const char *path) { int _FAT_unlink_r ( struct _reent *r, const char *path )
{
PARTITION* partition = NULL; PARTITION* partition = NULL;
DIR_ENTRY dirEntry; DIR_ENTRY dirEntry;
DIR_ENTRY dirContents; DIR_ENTRY dirContents;
@ -96,22 +103,26 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
// Get the partition this directory is on // Get the partition this directory is on
partition = _FAT_partition_getPartitionFromPath ( path ); partition = _FAT_partition_getPartitionFromPath ( path );
if (partition == NULL) { if ( partition == NULL )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
// Make sure we aren't trying to write to a read-only disc // Make sure we aren't trying to write to a read-only disc
if (partition->readOnly) { if ( partition->readOnly )
{
r->_errno = EROFS; r->_errno = EROFS;
return -1; return -1;
} }
// Move the path pointer to the start of the actual path // Move the path pointer to the start of the actual path
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
path = strchr ( path, ':' ) + 1; path = strchr ( path, ':' ) + 1;
} }
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -119,7 +130,8 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
_FAT_lock( &partition->lock ); _FAT_lock( &partition->lock );
// Search for the file on the disc // Search for the file on the disc
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) { if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
@ -129,11 +141,14 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
// If this is a directory, make sure it is empty // If this is a directory, make sure it is empty
if (_FAT_directory_isDirectory (&dirEntry)) { if ( _FAT_directory_isDirectory ( &dirEntry ) )
{
nextEntry = _FAT_directory_getFirstEntry ( partition, &dirContents, cluster ); nextEntry = _FAT_directory_getFirstEntry ( partition, &dirContents, cluster );
while (nextEntry) { while ( nextEntry )
if (!_FAT_directory_isDot (&dirContents)) { {
if ( !_FAT_directory_isDot ( &dirContents ) )
{
// The directory had something in it that isn't a reference to itself or it's parent // The directory had something in it that isn't a reference to itself or it's parent
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EPERM; r->_errno = EPERM;
@ -143,49 +158,60 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
} }
} }
if (_FAT_fat_isValidCluster(partition, cluster)) { if ( _FAT_fat_isValidCluster( partition, cluster ) )
{
// Remove the cluster chain for this file // Remove the cluster chain for this file
if (!_FAT_fat_clearLinks (partition, cluster)) { if ( !_FAT_fat_clearLinks ( partition, cluster ) )
{
r->_errno = EIO; r->_errno = EIO;
errorOccured = true; errorOccured = true;
} }
} }
// Remove the directory entry for this file // Remove the directory entry for this file
if (!_FAT_directory_removeEntry (partition, &dirEntry)) { if ( !_FAT_directory_removeEntry ( partition, &dirEntry ) )
{
r->_errno = EIO; r->_errno = EIO;
errorOccured = true; errorOccured = true;
} }
// Flush any sectors in the disc cache // Flush any sectors in the disc cache
if (!_FAT_cache_flush(partition->cache)) { if ( !_FAT_cache_flush( partition->cache ) )
{
r->_errno = EIO; r->_errno = EIO;
errorOccured = true; errorOccured = true;
} }
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
if (errorOccured) { if ( errorOccured )
{
return -1; return -1;
} else { }
else
{
return 0; return 0;
} }
} }
int _FAT_chdir_r (struct _reent *r, const char *path) { int _FAT_chdir_r ( struct _reent *r, const char *path )
{
PARTITION* partition = NULL; PARTITION* partition = NULL;
// Get the partition this directory is on // Get the partition this directory is on
partition = _FAT_partition_getPartitionFromPath ( path ); partition = _FAT_partition_getPartitionFromPath ( path );
if (partition == NULL) { if ( partition == NULL )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
// Move the path pointer to the start of the actual path // Move the path pointer to the start of the actual path
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
path = strchr ( path, ':' ) + 1; path = strchr ( path, ':' ) + 1;
} }
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -193,11 +219,14 @@ int _FAT_chdir_r (struct _reent *r, const char *path) {
_FAT_lock( &partition->lock ); _FAT_lock( &partition->lock );
// Try changing directory // Try changing directory
if (_FAT_directory_chdir (partition, path)) { if ( _FAT_directory_chdir ( partition, path ) )
{
// Successful // Successful
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
return 0; return 0;
} else { }
else
{
// Failed // Failed
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOTDIR; r->_errno = ENOTDIR;
@ -205,7 +234,8 @@ int _FAT_chdir_r (struct _reent *r, const char *path) {
} }
} }
int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) { int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName )
{
PARTITION* partition = NULL; PARTITION* partition = NULL;
DIR_ENTRY oldDirEntry; DIR_ENTRY oldDirEntry;
DIR_ENTRY newDirEntry; DIR_ENTRY newDirEntry;
@ -214,7 +244,8 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
// Get the partition this directory is on // Get the partition this directory is on
partition = _FAT_partition_getPartitionFromPath ( oldName ); partition = _FAT_partition_getPartitionFromPath ( oldName );
if (partition == NULL) { if ( partition == NULL )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -222,46 +253,54 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
_FAT_lock( &partition->lock ); _FAT_lock( &partition->lock );
// Make sure the same partition is used for the old and new names // Make sure the same partition is used for the old and new names
if (partition != _FAT_partition_getPartitionFromPath (newName)) { if ( partition != _FAT_partition_getPartitionFromPath ( newName ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EXDEV; r->_errno = EXDEV;
return -1; return -1;
} }
// Make sure we aren't trying to write to a read-only disc // Make sure we aren't trying to write to a read-only disc
if (partition->readOnly) { if ( partition->readOnly )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EROFS; r->_errno = EROFS;
return -1; return -1;
} }
// Move the path pointer to the start of the actual path // Move the path pointer to the start of the actual path
if (strchr (oldName, ':') != NULL) { if ( strchr ( oldName, ':' ) != NULL )
{
oldName = strchr ( oldName, ':' ) + 1; oldName = strchr ( oldName, ':' ) + 1;
} }
if (strchr (oldName, ':') != NULL) { if ( strchr ( oldName, ':' ) != NULL )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
if (strchr (newName, ':') != NULL) { if ( strchr ( newName, ':' ) != NULL )
{
newName = strchr ( newName, ':' ) + 1; newName = strchr ( newName, ':' ) + 1;
} }
if (strchr (newName, ':') != NULL) { if ( strchr ( newName, ':' ) != NULL )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
// Search for the file on the disc // Search for the file on the disc
if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL)) { if ( !_FAT_directory_entryFromPath ( partition, &oldDirEntry, oldName, NULL ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
} }
// Make sure there is no existing file / directory with the new name // Make sure there is no existing file / directory with the new name
if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL)) { if ( _FAT_directory_entryFromPath ( partition, &newDirEntry, newName, NULL ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EEXIST; r->_errno = EEXIST;
return -1; return -1;
@ -270,15 +309,19 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
// Create the new file entry // Create the new file entry
// Get the directory it has to go in // Get the directory it has to go in
pathEnd = strrchr ( newName, DIR_SEPARATOR ); pathEnd = strrchr ( newName, DIR_SEPARATOR );
if (pathEnd == NULL) { if ( pathEnd == NULL )
{
// No path was specified // No path was specified
dirCluster = partition->cwdCluster; dirCluster = partition->cwdCluster;
pathEnd = newName; pathEnd = newName;
} else { }
else
{
// Path was specified -- get the right dirCluster // Path was specified -- get the right dirCluster
// Recycling newDirEntry, since it needs to be recreated anyway // Recycling newDirEntry, since it needs to be recreated anyway
if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) || if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) ||
!_FAT_directory_isDirectory(&newDirEntry)) { !_FAT_directory_isDirectory( &newDirEntry ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOTDIR; r->_errno = ENOTDIR;
return -1; return -1;
@ -295,21 +338,24 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
strncpy ( newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 ); strncpy ( newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 );
// Write the new entry // Write the new entry
if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster)) { if ( !_FAT_directory_addEntry ( partition, &newDirEntry, dirCluster ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOSPC; r->_errno = ENOSPC;
return -1; return -1;
} }
// Remove the old entry // Remove the old entry
if (!_FAT_directory_removeEntry (partition, &oldDirEntry)) { if ( !_FAT_directory_removeEntry ( partition, &oldDirEntry ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EIO; r->_errno = EIO;
return -1; return -1;
} }
// Flush any sectors in the disc cache // Flush any sectors in the disc cache
if (!_FAT_cache_flush (partition->cache)) { if ( !_FAT_cache_flush ( partition->cache ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EIO; r->_errno = EIO;
return -1; return -1;
@ -319,7 +365,8 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
return 0; return 0;
} }
int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
{
PARTITION* partition = NULL; PARTITION* partition = NULL;
bool fileExists; bool fileExists;
DIR_ENTRY dirEntry; DIR_ENTRY dirEntry;
@ -328,16 +375,19 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE]; uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
partition = _FAT_partition_getPartitionFromPath ( path ); partition = _FAT_partition_getPartitionFromPath ( path );
if (partition == NULL) { if ( partition == NULL )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
// Move the path pointer to the start of the actual path // Move the path pointer to the start of the actual path
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
path = strchr ( path, ':' ) + 1; path = strchr ( path, ':' ) + 1;
} }
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -348,13 +398,15 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
fileExists = _FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ); fileExists = _FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL );
// Make sure it doesn't exist // Make sure it doesn't exist
if (fileExists) { if ( fileExists )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EEXIST; r->_errno = EEXIST;
return -1; return -1;
} }
if (partition->readOnly) { if ( partition->readOnly )
{
// We can't write to a read-only partition // We can't write to a read-only partition
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EROFS; r->_errno = EROFS;
@ -363,15 +415,19 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
// Get the directory it has to go in // Get the directory it has to go in
pathEnd = strrchr ( path, DIR_SEPARATOR ); pathEnd = strrchr ( path, DIR_SEPARATOR );
if (pathEnd == NULL) { if ( pathEnd == NULL )
{
// No path was specified // No path was specified
parentCluster = partition->cwdCluster; parentCluster = partition->cwdCluster;
pathEnd = path; pathEnd = path;
} else { }
else
{
// Path was specified -- get the right parentCluster // Path was specified -- get the right parentCluster
// Recycling dirEntry, since it needs to be recreated anyway // Recycling dirEntry, since it needs to be recreated anyway
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) || if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
!_FAT_directory_isDirectory(&dirEntry)) { !_FAT_directory_isDirectory( &dirEntry ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOTDIR; r->_errno = ENOTDIR;
return -1; return -1;
@ -397,7 +453,8 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
// Get a cluster for the new directory // Get a cluster for the new directory
dirCluster = _FAT_fat_linkFreeClusterCleared ( partition, CLUSTER_FREE ); dirCluster = _FAT_fat_linkFreeClusterCleared ( partition, CLUSTER_FREE );
if (!_FAT_fat_isValidCluster(partition, dirCluster)) { if ( !_FAT_fat_isValidCluster( partition, dirCluster ) )
{
// No space left on disc for the cluster // No space left on disc for the cluster
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOSPC; r->_errno = ENOSPC;
@ -407,7 +464,8 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16 ); u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16 );
// Write the new directory's entry to it's parent // Write the new directory's entry to it's parent
if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster)) { if ( !_FAT_directory_addEntry ( partition, &dirEntry, parentCluster ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = ENOSPC; r->_errno = ENOSPC;
return -1; return -1;
@ -441,7 +499,8 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
_FAT_fat_clusterToSector ( partition, dirCluster ), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE ); _FAT_fat_clusterToSector ( partition, dirCluster ), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
// Flush any sectors in the disc cache // Flush any sectors in the disc cache
if (!_FAT_cache_flush(partition->cache)) { if ( !_FAT_cache_flush( partition->cache ) )
{
_FAT_unlock( &partition->lock ); _FAT_unlock( &partition->lock );
r->_errno = EIO; r->_errno = EIO;
return -1; return -1;
@ -458,7 +517,8 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
// Get the partition of the requested path // Get the partition of the requested path
partition = _FAT_partition_getPartitionFromPath ( path ); partition = _FAT_partition_getPartitionFromPath ( path );
if (partition == NULL) { if ( partition == NULL )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -493,22 +553,26 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
return 0; return 0;
} }
DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) { DIR_ITER* _FAT_diropen_r( struct _reent *r, DIR_ITER *dirState, const char *path )
{
DIR_ENTRY dirEntry; DIR_ENTRY dirEntry;
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct ); DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
bool fileExists; bool fileExists;
state->partition = _FAT_partition_getPartitionFromPath ( path ); state->partition = _FAT_partition_getPartitionFromPath ( path );
if (state->partition == NULL) { if ( state->partition == NULL )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return NULL; return NULL;
} }
// Move the path pointer to the start of the actual path // Move the path pointer to the start of the actual path
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
path = strchr ( path, ':' ) + 1; path = strchr ( path, ':' ) + 1;
} }
if (strchr (path, ':') != NULL) { if ( strchr ( path, ':' ) != NULL )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return NULL; return NULL;
} }
@ -518,14 +582,16 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
// Get the start cluster of the directory // Get the start cluster of the directory
fileExists = _FAT_directory_entryFromPath ( state->partition, &dirEntry, path, NULL ); fileExists = _FAT_directory_entryFromPath ( state->partition, &dirEntry, path, NULL );
if (!fileExists) { if ( !fileExists )
{
_FAT_unlock( &state->partition->lock ); _FAT_unlock( &state->partition->lock );
r->_errno = ENOENT; r->_errno = ENOENT;
return NULL; return NULL;
} }
// Make sure it is a directory // Make sure it is a directory
if (! _FAT_directory_isDirectory (&dirEntry)) { if ( ! _FAT_directory_isDirectory ( &dirEntry ) )
{
_FAT_unlock( &state->partition->lock ); _FAT_unlock( &state->partition->lock );
r->_errno = ENOTDIR; r->_errno = ENOTDIR;
return NULL; return NULL;
@ -544,13 +610,15 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
return ( DIR_ITER* ) state; return ( DIR_ITER* ) state;
} }
int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) { int _FAT_dirreset_r ( struct _reent *r, DIR_ITER *dirState )
{
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct ); DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
_FAT_lock( &state->partition->lock ); _FAT_lock( &state->partition->lock );
// Make sure we are still using this entry // Make sure we are still using this entry
if (!state->inUse) { if ( !state->inUse )
{
_FAT_unlock( &state->partition->lock ); _FAT_unlock( &state->partition->lock );
r->_errno = EBADF; r->_errno = EBADF;
return -1; return -1;
@ -564,20 +632,23 @@ int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) {
return 0; return 0;
} }
int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) { int _FAT_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat )
{
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct ); DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
_FAT_lock( &state->partition->lock ); _FAT_lock( &state->partition->lock );
// Make sure we are still using this entry // Make sure we are still using this entry
if (!state->inUse) { if ( !state->inUse )
{
_FAT_unlock( &state->partition->lock ); _FAT_unlock( &state->partition->lock );
r->_errno = EBADF; r->_errno = EBADF;
return -1; return -1;
} }
// Make sure there is another file to report on // Make sure there is another file to report on
if (! state->validEntry) { if ( ! state->validEntry )
{
_FAT_unlock( &state->partition->lock ); _FAT_unlock( &state->partition->lock );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
@ -586,7 +657,8 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
// Get the filename // Get the filename
strncpy ( filename, state->currentEntry.filename, MAX_FILENAME_LENGTH ); strncpy ( filename, state->currentEntry.filename, MAX_FILENAME_LENGTH );
// Get the stats, if requested // Get the stats, if requested
if (filestat != NULL) { if ( filestat != NULL )
{
_FAT_directory_entryStat ( state->partition, &( state->currentEntry ), filestat ); _FAT_directory_entryStat ( state->partition, &( state->currentEntry ), filestat );
} }
@ -598,7 +670,8 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
return 0; return 0;
} }
int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState) { int _FAT_dirclose_r ( struct _reent *r, DIR_ITER *dirState )
{
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct ); DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
// We are no longer using this entry // We are no longer using this entry

View File

@ -39,7 +39,8 @@
#include "common.h" #include "common.h"
#include "directory.h" #include "directory.h"
typedef struct { typedef struct
{
PARTITION* partition; PARTITION* partition;
DIR_ENTRY currentEntry; DIR_ENTRY currentEntry;
uint32_t startCluster; uint32_t startCluster;

File diff suppressed because it is too large Load Diff

View File

@ -41,7 +41,8 @@
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B #define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
typedef struct { typedef struct
{
u32 cluster; u32 cluster;
sec_t sector; sec_t sector;
s32 byte; s32 byte;
@ -49,7 +50,8 @@ typedef struct {
struct _FILE_STRUCT; struct _FILE_STRUCT;
struct _FILE_STRUCT { struct _FILE_STRUCT
{
uint32_t filesize; uint32_t filesize;
uint32_t startCluster; uint32_t startCluster;
uint32_t currentPosition; uint32_t currentPosition;

View File

@ -41,7 +41,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
sec_t sector; sec_t sector;
int offset; int offset;
if (cluster == CLUSTER_FREE) { if ( cluster == CLUSTER_FREE )
{
return CLUSTER_FREE; return CLUSTER_FREE;
} }
@ -62,7 +63,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
offset++; offset++;
if (offset >= BYTES_PER_READ) { if ( offset >= BYTES_PER_READ )
{
offset = 0; offset = 0;
sector++; sector++;
} }
@ -71,9 +73,12 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster_h, sector, offset, sizeof( u8 ) ); _FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster_h, sector, offset, sizeof( u8 ) );
nextCluster |= ( nextCluster_h << 8 ); nextCluster |= ( nextCluster_h << 8 );
if (cluster & 0x01) { if ( cluster & 0x01 )
{
nextCluster = nextCluster >> 4; nextCluster = nextCluster >> 4;
} else { }
else
{
nextCluster &= 0x0FFF; nextCluster &= 0x0FFF;
} }
@ -90,7 +95,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u16 ) ); _FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u16 ) );
if (nextCluster >= 0xFFF7) { if ( nextCluster >= 0xFFF7 )
{
nextCluster = CLUSTER_EOF; nextCluster = CLUSTER_EOF;
} }
break; break;
@ -101,7 +107,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u32 ) ); _FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u32 ) );
if (nextCluster >= 0x0FFFFFF7) { if ( nextCluster >= 0x0FFFFFF7 )
{
nextCluster = CLUSTER_EOF; nextCluster = CLUSTER_EOF;
} }
break; break;
@ -118,7 +125,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
writes value into the correct offset within a partition's FAT, based writes value into the correct offset within a partition's FAT, based
on the cluster number. on the cluster number.
*/ */
static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value) { static bool _FAT_fat_writeFatEntry ( PARTITION* partition, uint32_t cluster, uint32_t value )
{
sec_t sector; sec_t sector;
int offset; int offset;
uint32_t oldValue; uint32_t oldValue;
@ -138,7 +146,8 @@ static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint
sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ ); sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ );
offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ; offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ;
if (cluster & 0x01) { if ( cluster & 0x01 )
{
_FAT_cache_readLittleEndianValue ( partition->cache, &oldValue, sector, offset, sizeof( u8 ) ); _FAT_cache_readLittleEndianValue ( partition->cache, &oldValue, sector, offset, sizeof( u8 ) );
@ -147,19 +156,23 @@ static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint
_FAT_cache_writeLittleEndianValue ( partition->cache, value & 0xFF, sector, offset, sizeof( u8 ) ); _FAT_cache_writeLittleEndianValue ( partition->cache, value & 0xFF, sector, offset, sizeof( u8 ) );
offset++; offset++;
if (offset >= BYTES_PER_READ) { if ( offset >= BYTES_PER_READ )
{
offset = 0; offset = 0;
sector++; sector++;
} }
_FAT_cache_writeLittleEndianValue ( partition->cache, ( value >> 8 ) & 0xFF, sector, offset, sizeof( u8 ) ); _FAT_cache_writeLittleEndianValue ( partition->cache, ( value >> 8 ) & 0xFF, sector, offset, sizeof( u8 ) );
} else { }
else
{
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) ); _FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) );
offset++; offset++;
if (offset >= BYTES_PER_READ) { if ( offset >= BYTES_PER_READ )
{
offset = 0; offset = 0;
sector++; sector++;
} }
@ -203,7 +216,8 @@ to end of file, links the input cluster to it then returns the
cluster number cluster number
If an error occurs, return CLUSTER_ERROR If an error occurs, return CLUSTER_ERROR
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) { uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
{
uint32_t firstFree; uint32_t firstFree;
uint32_t curLink; uint32_t curLink;
uint32_t lastCluster; uint32_t lastCluster;
@ -211,32 +225,40 @@ uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
lastCluster = partition->fat.lastCluster; lastCluster = partition->fat.lastCluster;
if (cluster > lastCluster) { if ( cluster > lastCluster )
{
return CLUSTER_ERROR; return CLUSTER_ERROR;
} }
// Check if the cluster already has a link, and return it if so // Check if the cluster already has a link, and return it if so
curLink = _FAT_fat_nextCluster( partition, cluster ); curLink = _FAT_fat_nextCluster( partition, cluster );
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster)) { if ( ( curLink >= CLUSTER_FIRST ) && ( curLink <= lastCluster ) )
{
return curLink; // Return the current link - don't allocate a new one return curLink; // Return the current link - don't allocate a new one
} }
// Get a free cluster // Get a free cluster
firstFree = partition->fat.firstFree; firstFree = partition->fat.firstFree;
// Start at first valid cluster // Start at first valid cluster
if (firstFree < CLUSTER_FIRST) { if ( firstFree < CLUSTER_FIRST )
{
firstFree = CLUSTER_FIRST; firstFree = CLUSTER_FIRST;
} }
// Search until a free cluster is found // Search until a free cluster is found
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) { while ( _FAT_fat_nextCluster( partition, firstFree ) != CLUSTER_FREE )
{
firstFree++; firstFree++;
if (firstFree > lastCluster) { if ( firstFree > lastCluster )
if (loopedAroundFAT) { {
if ( loopedAroundFAT )
{
// If couldn't get a free cluster then return an error // If couldn't get a free cluster then return an error
partition->fat.firstFree = firstFree; partition->fat.firstFree = firstFree;
return CLUSTER_ERROR; return CLUSTER_ERROR;
} else { }
else
{
// Try looping back to the beginning of the FAT // Try looping back to the beginning of the FAT
// This was suggested by loopy // This was suggested by loopy
firstFree = CLUSTER_FIRST; firstFree = CLUSTER_FIRST;
@ -263,7 +285,8 @@ to end of file, links the input cluster to it, clears the new
cluster to 0 valued bytes, then returns the cluster number cluster to 0 valued bytes, then returns the cluster number
If an error occurs, return CLUSTER_ERROR If an error occurs, return CLUSTER_ERROR
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster) { uint32_t _FAT_fat_linkFreeClusterCleared ( PARTITION* partition, uint32_t cluster )
{
uint32_t newCluster; uint32_t newCluster;
uint32_t i; uint32_t i;
uint8_t emptySector[BYTES_PER_READ]; uint8_t emptySector[BYTES_PER_READ];
@ -271,13 +294,15 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster
// Link the cluster // Link the cluster
newCluster = _FAT_fat_linkFreeCluster( partition, cluster ); newCluster = _FAT_fat_linkFreeCluster( partition, cluster );
if (newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR) { if ( newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR )
{
return CLUSTER_ERROR; return CLUSTER_ERROR;
} }
// Clear all the sectors within the cluster // Clear all the sectors within the cluster
memset ( emptySector, 0, BYTES_PER_READ ); memset ( emptySector, 0, BYTES_PER_READ );
for (i = 0; i < partition->sectorsPerCluster; i++) { for ( i = 0; i < partition->sectorsPerCluster; i++ )
{
_FAT_cache_writeSectors ( partition->cache, _FAT_cache_writeSectors ( partition->cache,
_FAT_fat_clusterToSector ( partition, newCluster ) + i, _FAT_fat_clusterToSector ( partition, newCluster ) + i,
1, emptySector ); 1, emptySector );
@ -291,18 +316,21 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster
_FAT_fat_clearLinks _FAT_fat_clearLinks
frees any cluster used by a file frees any cluster used by a file
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster) { bool _FAT_fat_clearLinks ( PARTITION* partition, uint32_t cluster )
{
uint32_t nextCluster; uint32_t nextCluster;
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) ) if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
return false; return false;
// If this clears up more space in the FAT before the current free pointer, move it backwards // If this clears up more space in the FAT before the current free pointer, move it backwards
if (cluster < partition->fat.firstFree) { if ( cluster < partition->fat.firstFree )
{
partition->fat.firstFree = cluster; partition->fat.firstFree = cluster;
} }
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR)) { while ( ( cluster != CLUSTER_EOF ) && ( cluster != CLUSTER_FREE ) && ( cluster != CLUSTER_ERROR ) )
{
// Store next cluster before erasing the link // Store next cluster before erasing the link
nextCluster = _FAT_fat_nextCluster ( partition, cluster ); nextCluster = _FAT_fat_nextCluster ( partition, cluster );
@ -324,25 +352,31 @@ If chainLength is 1, the first cluster is kept and the rest are
dropped, and so on. dropped, and so on.
Return the last cluster left in the chain. Return the last cluster left in the chain.
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength) { uint32_t _FAT_fat_trimChain ( PARTITION* partition, uint32_t startCluster, unsigned int chainLength )
{
uint32_t nextCluster; uint32_t nextCluster;
if (chainLength == 0) { if ( chainLength == 0 )
{
// Drop the entire chain // Drop the entire chain
_FAT_fat_clearLinks ( partition, startCluster ); _FAT_fat_clearLinks ( partition, startCluster );
return CLUSTER_FREE; return CLUSTER_FREE;
} else { }
else
{
// Find the last cluster in the chain, and the one after it // Find the last cluster in the chain, and the one after it
chainLength--; chainLength--;
nextCluster = _FAT_fat_nextCluster ( partition, startCluster ); nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) { while ( ( chainLength > 0 ) && ( nextCluster != CLUSTER_FREE ) && ( nextCluster != CLUSTER_EOF ) )
{
chainLength--; chainLength--;
startCluster = nextCluster; startCluster = nextCluster;
nextCluster = _FAT_fat_nextCluster ( partition, startCluster ); nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
} }
// Drop all clusters after the last in the chain // Drop all clusters after the last in the chain
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF) { if ( nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF )
{
_FAT_fat_clearLinks ( partition, nextCluster ); _FAT_fat_clearLinks ( partition, nextCluster );
} }
@ -357,8 +391,10 @@ uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsign
_FAT_fat_lastCluster _FAT_fat_lastCluster
Trace the cluster links until the last one is found Trace the cluster links until the last one is found
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) { uint32_t _FAT_fat_lastCluster ( PARTITION* partition, uint32_t cluster )
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF)) { {
while ( ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_FREE ) && ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_EOF ) )
{
cluster = _FAT_fat_nextCluster( partition, cluster ); cluster = _FAT_fat_nextCluster( partition, cluster );
} }
return cluster; return cluster;
@ -368,12 +404,15 @@ uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
_FAT_fat_freeClusterCount _FAT_fat_freeClusterCount
Return the number of free clusters available Return the number of free clusters available
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition) { unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition )
{
unsigned int count = 0; unsigned int count = 0;
uint32_t curCluster; uint32_t curCluster;
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++) { for ( curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++ )
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE) { {
if ( _FAT_fat_nextCluster( partition, curCluster ) == CLUSTER_FREE )
{
count++; count++;
} }
} }

View File

@ -57,13 +57,15 @@ uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster);
unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition ); unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition );
static inline sec_t _FAT_fat_clusterToSector (PARTITION* partition, uint32_t cluster) { static inline sec_t _FAT_fat_clusterToSector ( PARTITION* partition, uint32_t cluster )
{
return ( cluster >= CLUSTER_FIRST ) ? return ( cluster >= CLUSTER_FIRST ) ?
( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart : ( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart :
partition->rootDirStart; partition->rootDirStart;
} }
static inline bool _FAT_fat_isValidCluster (PARTITION* partition, uint32_t cluster) { static inline bool _FAT_fat_isValidCluster ( PARTITION* partition, uint32_t cluster )
{
return ( cluster >= CLUSTER_FIRST ) && ( cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ); return ( cluster >= CLUSTER_FIRST ) && ( cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ );
} }

View File

@ -40,12 +40,14 @@
#define MAX_DAY 31 #define MAX_DAY 31
#define MIN_DAY 1 #define MIN_DAY 1
uint16_t _FAT_filetime_getTimeFromRTC (void) { uint16_t _FAT_filetime_getTimeFromRTC ( void )
{
#ifdef USE_RTC_TIME #ifdef USE_RTC_TIME
struct tm timeParts; struct tm timeParts;
time_t epochTime; time_t epochTime;
if (time(&epochTime) == (time_t)-1) { if ( time( &epochTime ) == ( time_t ) - 1 )
{
return 0; return 0;
} }
localtime_r( &epochTime, &timeParts ); localtime_r( &epochTime, &timeParts );
@ -67,12 +69,14 @@ uint16_t _FAT_filetime_getTimeFromRTC (void) {
} }
uint16_t _FAT_filetime_getDateFromRTC (void) { uint16_t _FAT_filetime_getDateFromRTC ( void )
{
#ifdef USE_RTC_TIME #ifdef USE_RTC_TIME
struct tm timeParts; struct tm timeParts;
time_t epochTime; time_t epochTime;
if (time(&epochTime) == (time_t)-1) { if ( time( &epochTime ) == ( time_t ) - 1 )
{
return 0; return 0;
} }
localtime_r( &epochTime, &timeParts ); localtime_r( &epochTime, &timeParts );
@ -90,7 +94,8 @@ uint16_t _FAT_filetime_getDateFromRTC (void) {
#endif #endif
} }
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d) { time_t _FAT_filetime_to_time_t ( uint16_t t, uint16_t d )
{
struct tm timeParts; struct tm timeParts;
timeParts.tm_hour = t >> 11; timeParts.tm_hour = t >> 11;

View File

@ -38,7 +38,8 @@
#include "mem_allocate.h" #include "mem_allocate.h"
#include "disc_fat.h" #include "disc_fat.h"
static const devoptab_t dotab_fat = { static const devoptab_t dotab_fat =
{
"fat", "fat",
sizeof ( FILE_STRUCT ), sizeof ( FILE_STRUCT ),
_FAT_open_r, _FAT_open_r,
@ -64,7 +65,8 @@ static const devoptab_t dotab_fat = {
NULL /* Device data */ NULL /* Device data */
}; };
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) { bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage )
{
PARTITION* partition; PARTITION* partition;
devoptab_t* devops; devoptab_t* devops;
char* nameCopy; char* nameCopy;
@ -72,13 +74,15 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
if ( !interface->startup() ) if ( !interface->startup() )
return false; return false;
if(!interface->isInserted()) { if ( !interface->isInserted() )
{
interface->shutdown(); interface->shutdown();
return false; return false;
} }
devops = _FAT_mem_allocate ( sizeof( devoptab_t ) + strlen( name ) + 1 ); devops = _FAT_mem_allocate ( sizeof( devoptab_t ) + strlen( name ) + 1 );
if (!devops) { if ( !devops )
{
interface->shutdown(); interface->shutdown();
return false; return false;
} }
@ -87,7 +91,8 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
// Initialize the file system // Initialize the file system
partition = _FAT_partition_constructor ( interface, cacheSize, SectorsPerPage, startSector ); partition = _FAT_partition_constructor ( interface, cacheSize, SectorsPerPage, startSector );
if (!partition) { if ( !partition )
{
_FAT_mem_free ( devops ); _FAT_mem_free ( devops );
interface->shutdown(); interface->shutdown();
return false; return false;
@ -104,26 +109,31 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
return true; return true;
} }
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) { bool fatMountSimple ( const char* name, const DISC_INTERFACE* interface )
{
return fatMount ( name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE ); return fatMount ( name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE );
} }
void fatUnmount (const char* name) { void fatUnmount ( const char* name )
{
devoptab_t *devops; devoptab_t *devops;
PARTITION* partition; PARTITION* partition;
const DISC_INTERFACE *disc; const DISC_INTERFACE *disc;
devops = ( devoptab_t* )GetDeviceOpTab ( name ); devops = ( devoptab_t* )GetDeviceOpTab ( name );
if (!devops) { if ( !devops )
{
return; return;
} }
// Perform a quick check to make sure we're dealing with a libfat controlled device // Perform a quick check to make sure we're dealing with a libfat controlled device
if (devops->open_r != dotab_fat.open_r) { if ( devops->open_r != dotab_fat.open_r )
{
return; return;
} }
if (RemoveDevice (name) == -1) { if ( RemoveDevice ( name ) == -1 )
{
return; return;
} }
@ -134,7 +144,8 @@ void fatUnmount (const char* name) {
disc->shutdown(); disc->shutdown();
} }
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) { bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
{
int i; int i;
int defaultDevice = -1; int defaultDevice = -1;
const DISC_INTERFACE *disc; const DISC_INTERFACE *disc;
@ -144,25 +155,30 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
i++ ) i++ )
{ {
disc = _FAT_disc_interfaces[i].getInterface(); disc = _FAT_disc_interfaces[i].getInterface();
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) { if ( fatMount ( _FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE ) )
{
// The first device to successfully mount is set as the default // The first device to successfully mount is set as the default
if (defaultDevice < 0) { if ( defaultDevice < 0 )
{
defaultDevice = i; defaultDevice = i;
} }
} }
} }
if (defaultDevice < 0) { if ( defaultDevice < 0 )
{
// None of our devices mounted // None of our devices mounted
return false; return false;
} }
if (setAsDefaultDevice) { if ( setAsDefaultDevice )
{
char filePath[MAXPATHLEN * 2]; char filePath[MAXPATHLEN * 2];
strcpy ( filePath, _FAT_disc_interfaces[defaultDevice].name ); strcpy ( filePath, _FAT_disc_interfaces[defaultDevice].name );
strcat ( filePath, ":/" ); strcat ( filePath, ":/" );
#ifdef ARGV_MAGIC #ifdef ARGV_MAGIC
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL ) { if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' ) != NULL )
{
// Check the app's path against each of our mounted devices, to see // Check the app's path against each of our mounted devices, to see
// if we can support it. If so, change to that path. // if we can support it. If so, change to that path.
for ( i = 0; for ( i = 0;
@ -176,7 +192,8 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
strcpy( filePath, __system_argv->argv[0] ); strcpy( filePath, __system_argv->argv[0] );
lastSlash = strrchr( filePath, '/' ); lastSlash = strrchr( filePath, '/' );
if ( NULL != lastSlash) { if ( NULL != lastSlash )
{
if ( *( lastSlash - 1 ) == ':' ) lastSlash++; if ( *( lastSlash - 1 ) == ':' ) lastSlash++;
*lastSlash = 0; *lastSlash = 0;
} }
@ -190,7 +207,8 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
return true; return true;
} }
bool fatInitDefault (void) { bool fatInitDefault ( void )
{
return fatInit ( DEFAULT_CACHE_PAGES, true ); return fatInit ( DEFAULT_CACHE_PAGES, true );
} }

View File

@ -33,16 +33,19 @@
#include <malloc.h> #include <malloc.h>
static inline void* _FAT_mem_allocate (size_t size) { static inline void* _FAT_mem_allocate ( size_t size )
{
return malloc ( size ); return malloc ( size );
} }
static inline void* _FAT_mem_align (size_t size) { static inline void* _FAT_mem_align ( size_t size )
{
return memalign ( 32, size ); return memalign ( 32, size );
} }
static inline void _FAT_mem_free (void* mem) { static inline void _FAT_mem_free ( void* mem )
{
free ( mem ); free ( mem );
} }

View File

@ -50,7 +50,8 @@ Data offsets
*/ */
// BIOS Parameter Block offsets // BIOS Parameter Block offsets
enum BPB { enum BPB
{
BPB_jmpBoot = 0x00, BPB_jmpBoot = 0x00,
BPB_OEMName = 0x03, BPB_OEMName = 0x03,
// BIOS Parameter Block // BIOS Parameter Block
@ -107,24 +108,28 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
uint8_t sectorBuffer[BYTES_PER_READ] = {0}; uint8_t sectorBuffer[BYTES_PER_READ] = {0};
// Read first sector of disc // Read first sector of disc
if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) { if ( !_FAT_disc_readSectors ( disc, 0, 1, sectorBuffer ) )
{
return 0; return 0;
} }
memcpy( part_table, sectorBuffer + 0x1BE, 16*4 ); memcpy( part_table, sectorBuffer + 0x1BE, 16*4 );
ptr = part_table; ptr = part_table;
for(i=0;i<4;i++,ptr+=16) { for ( i = 0; i < 4; i++, ptr += 16 )
{
sec_t part_lba = u8array_to_u32( ptr, 0x8 ); sec_t part_lba = u8array_to_u32( ptr, 0x8 );
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) || if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { !memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
{
return part_lba; return part_lba;
} }
if ( ptr[4] == 0 ) continue; if ( ptr[4] == 0 ) continue;
if(ptr[4]==0x0F) { if ( ptr[4] == 0x0F )
{
sec_t part_lba2 = part_lba; sec_t part_lba2 = part_lba;
sec_t next_lba2 = 0; sec_t next_lba2 = 0;
int n; int n;
@ -146,10 +151,13 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
if ( next_lba2 == 0 ) break; if ( next_lba2 == 0 ) break;
} }
} else { }
else
{
if ( !_FAT_disc_readSectors ( disc, part_lba, 1, sectorBuffer ) ) return 0; if ( !_FAT_disc_readSectors ( disc, part_lba, 1, sectorBuffer ) ) return 0;
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) || if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { !memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
{
return part_lba; return part_lba;
} }
} }
@ -157,31 +165,42 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
return 0; return 0;
} }
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) { PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector )
{
PARTITION* partition; PARTITION* partition;
uint8_t sectorBuffer[BYTES_PER_READ] = {0}; uint8_t sectorBuffer[BYTES_PER_READ] = {0};
// Read first sector of disc // Read first sector of disc
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
{
return NULL; return NULL;
} }
// Make sure it is a valid MBR or boot sector // Make sure it is a valid MBR or boot sector
if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) { if ( ( sectorBuffer[BPB_bootSig_55] != 0x55 ) || ( sectorBuffer[BPB_bootSig_AA] != 0xAA ) )
{
return NULL; return NULL;
} }
if (startSector != 0) { if ( startSector != 0 )
{
// We're told where to start the partition, so just accept it // We're told where to start the partition, so just accept it
} else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { }
else if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
{
// Check if there is a FAT string, which indicates this is a boot sector // Check if there is a FAT string, which indicates this is a boot sector
startSector = 0; startSector = 0;
} else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { }
else if ( !memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
{
// Check for FAT32 // Check for FAT32
startSector = 0; startSector = 0;
} else { }
else
{
startSector = FindFirstValidPartition( disc ); startSector = FindFirstValidPartition( disc );
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
{
return NULL; return NULL;
} }
} }
@ -201,7 +220,8 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
} }
partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) ); partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) );
if (partition == NULL) { if ( partition == NULL )
{
return NULL; return NULL;
} }
@ -215,12 +235,14 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
// Store required information about the file system // Store required information about the file system
partition->fat.sectorsPerFat = u8array_to_u16( sectorBuffer, BPB_sectorsPerFAT ); partition->fat.sectorsPerFat = u8array_to_u16( sectorBuffer, BPB_sectorsPerFAT );
if (partition->fat.sectorsPerFat == 0) { if ( partition->fat.sectorsPerFat == 0 )
{
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32 ); partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32 );
} }
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall ); partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall );
if (partition->numberOfSectors == 0) { if ( partition->numberOfSectors == 0 )
{
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors ); partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors );
} }
@ -240,21 +262,30 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1; partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
partition->fat.firstFree = CLUSTER_FIRST; partition->fat.firstFree = CLUSTER_FIRST;
if (clusterCount < CLUSTERS_PER_FAT12) { if ( clusterCount < CLUSTERS_PER_FAT12 )
{
partition->filesysType = FS_FAT12; // FAT12 volume partition->filesysType = FS_FAT12; // FAT12 volume
} else if (clusterCount < CLUSTERS_PER_FAT16) { }
else if ( clusterCount < CLUSTERS_PER_FAT16 )
{
partition->filesysType = FS_FAT16; // FAT16 volume partition->filesysType = FS_FAT16; // FAT16 volume
} else { }
else
{
partition->filesysType = FS_FAT32; // FAT32 volume partition->filesysType = FS_FAT32; // FAT32 volume
} }
if (partition->filesysType != FS_FAT32) { if ( partition->filesysType != FS_FAT32 )
{
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER; partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
} else { }
else
{
// Set up for the FAT32 way // Set up for the FAT32 way
partition->rootDirCluster = u8array_to_u32( sectorBuffer, BPB_FAT32_rootClus ); partition->rootDirCluster = u8array_to_u32( sectorBuffer, BPB_FAT32_rootClus );
// Check if FAT mirroring is enabled // Check if FAT mirroring is enabled
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) { if ( !( sectorBuffer[BPB_FAT32_extFlags] & 0x80 ) )
{
// Use the active FAT // Use the active FAT
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * ( sectorBuffer[BPB_FAT32_extFlags] & 0x0F ) ); partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * ( sectorBuffer[BPB_FAT32_extFlags] & 0x0F ) );
} }
@ -276,14 +307,16 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
return partition; return partition;
} }
void _FAT_partition_destructor (PARTITION* partition) { void _FAT_partition_destructor ( PARTITION* partition )
{
FILE_STRUCT* nextFile; FILE_STRUCT* nextFile;
_FAT_lock( &partition->lock ); _FAT_lock( &partition->lock );
// Synchronize open files // Synchronize open files
nextFile = partition->firstOpenFile; nextFile = partition->firstOpenFile;
while (nextFile) { while ( nextFile )
{
_FAT_syncToDisc ( nextFile ); _FAT_syncToDisc ( nextFile );
nextFile = nextFile->nextOpenFile; nextFile = nextFile->nextOpenFile;
} }
@ -299,12 +332,14 @@ void _FAT_partition_destructor (PARTITION* partition) {
_FAT_mem_free ( partition ); _FAT_mem_free ( partition );
} }
PARTITION* _FAT_partition_getPartitionFromPath (const char* path) { PARTITION* _FAT_partition_getPartitionFromPath ( const char* path )
{
const devoptab_t *devops; const devoptab_t *devops;
devops = GetDeviceOpTab ( path ); devops = GetDeviceOpTab ( path );
if (!devops) { if ( !devops )
{
return NULL; return NULL;
} }

View File

@ -40,14 +40,16 @@ extern const char* DEVICE_NAME;
// Filesystem type // Filesystem type
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE; typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
typedef struct { typedef struct
{
sec_t fatStart; sec_t fatStart;
uint32_t sectorsPerFat; uint32_t sectorsPerFat;
uint32_t lastCluster; uint32_t lastCluster;
uint32_t firstFree; uint32_t firstFree;
} FAT; } FAT;
typedef struct { typedef struct
{
const DISC_INTERFACE* disc; const DISC_INTERFACE* disc;
CACHE* cache; CACHE* cache;
// Info about the partition // Info about the partition

File diff suppressed because it is too large Load Diff

View File

@ -122,7 +122,8 @@ typedef char BIGSID[40];
* (private to this module) * (private to this module)
*/ */
struct MAPLIST { struct MAPLIST
{
struct MAPLIST *next; struct MAPLIST *next;
char *uidstr; /* uid text from the same record */ char *uidstr; /* uid text from the same record */
char *gidstr; /* gid text from the same record */ char *gidstr; /* gid text from the same record */

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,8 @@ extern ntfschar TXF_DATA[10];
* *
* TODO: Describe them. * TODO: Describe them.
*/ */
typedef enum { typedef enum
{
LCN_HOLE = -1, /* Keep this as highest value or die! */ LCN_HOLE = -1, /* Keep this as highest value or die! */
LCN_RL_NOT_MAPPED = -2, LCN_RL_NOT_MAPPED = -2,
LCN_ENOENT = -3, LCN_ENOENT = -3,
@ -75,7 +76,8 @@ typedef enum {
* any modification of the search context, to automagically get the next * any modification of the search context, to automagically get the next
* matching attribute. * matching attribute.
*/ */
struct _ntfs_attr_search_ctx { struct _ntfs_attr_search_ctx
{
MFT_RECORD *mrec; MFT_RECORD *mrec;
ATTR_RECORD *attr; ATTR_RECORD *attr;
BOOL is_first; BOOL is_first;
@ -174,7 +176,8 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
* @state contains NTFS attribute specific flags describing this attribute * @state contains NTFS attribute specific flags describing this attribute
* structure. See ntfs_attr_state_bits above. * structure. See ntfs_attr_state_bits above.
*/ */
struct _ntfs_attr { struct _ntfs_attr
{
runlist_element *rl; runlist_element *rl;
ntfs_inode *ni; ntfs_inode *ni;
ATTR_TYPES type; ATTR_TYPES type;
@ -196,7 +199,8 @@ struct _ntfs_attr {
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr * enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
* structure * structure
*/ */
typedef enum { typedef enum
{
NA_Initialized, /* 1: structure is initialized. */ NA_Initialized, /* 1: structure is initialized. */
NA_NonResident, /* 1: Attribute is not resident. */ NA_NonResident, /* 1: Attribute is not resident. */
NA_BeingNonResident, /* 1: Attribute is being made not resident. */ NA_BeingNonResident, /* 1: Attribute is being made not resident. */
@ -243,7 +247,8 @@ GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
* *
* For convenience. Used in the attr structure. * For convenience. Used in the attr structure.
*/ */
typedef union { typedef union
{
u8 _default; /* Unnamed u8 to serve as default when just using u8 _default; /* Unnamed u8 to serve as default when just using
a_val without specifying any of the below. */ a_val without specifying any of the below. */
STANDARD_INFORMATION std_inf; STANDARD_INFORMATION std_inf;

File diff suppressed because it is too large Load Diff

View File

@ -62,7 +62,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
{ {
ATTR_LIST_ENTRY *ale; ATTR_LIST_ENTRY *ale;
if (!ni) { if ( !ni )
{
ntfs_log_trace( "Invalid arguments.\n" ); ntfs_log_trace( "Invalid arguments.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -70,13 +71,15 @@ int ntfs_attrlist_need(ntfs_inode *ni)
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no ); ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
if (!NInoAttrList(ni)) { if ( !NInoAttrList( ni ) )
{
ntfs_log_trace( "Inode haven't got attribute list.\n" ); ntfs_log_trace( "Inode haven't got attribute list.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (!ni->attr_list) { if ( !ni->attr_list )
{
ntfs_log_trace( "Corrupt in-memory struct.\n" ); ntfs_log_trace( "Corrupt in-memory struct.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -84,7 +87,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
errno = 0; errno = 0;
ale = ( ATTR_LIST_ENTRY * )ni->attr_list; ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
while ((u8*)ale < ni->attr_list + ni->attr_list_size) { while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
{
if ( MREF_LE( ale->mft_reference ) != ni->mft_no ) if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
return 1; return 1;
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) ); ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
@ -117,7 +121,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
( long long ) ni->mft_no, ( long long ) ni->mft_no,
( unsigned ) le32_to_cpu( attr->type ) ); ( unsigned ) le32_to_cpu( attr->type ) );
if (!ni || !attr) { if ( !ni || !attr )
{
ntfs_log_trace( "Invalid arguments.\n" ); ntfs_log_trace( "Invalid arguments.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -128,7 +133,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
if ( ni->nr_extents == -1 ) if ( ni->nr_extents == -1 )
ni = ni->base_ni; ni = ni->base_ni;
if (!NInoAttrList(ni)) { if ( !NInoAttrList( ni ) )
{
ntfs_log_trace( "Attribute list isn't present.\n" ); ntfs_log_trace( "Attribute list isn't present.\n" );
errno = ENOENT; errno = ENOENT;
return -1; return -1;
@ -143,7 +149,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
/* Find place for the new entry. */ /* Find place for the new entry. */
ctx = ntfs_attr_get_search_ctx( ni, NULL ); ctx = ntfs_attr_get_search_ctx( ni, NULL );
if (!ctx) { if ( !ctx )
{
err = errno; err = errno;
goto err_out; goto err_out;
} }
@ -153,9 +160,11 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
( attr->non_resident ) ? le64_to_cpu( attr->lowest_vcn ) : ( attr->non_resident ) ? le64_to_cpu( attr->lowest_vcn ) :
0, ( attr->non_resident ) ? NULL : ( ( u8* )attr + 0, ( attr->non_resident ) ? NULL : ( ( u8* )attr +
le16_to_cpu( attr->value_offset ) ), ( attr->non_resident ) ? le16_to_cpu( attr->value_offset ) ), ( attr->non_resident ) ?
0 : le32_to_cpu(attr->value_length), ctx)) { 0 : le32_to_cpu( attr->value_length ), ctx ) )
{
/* Found some extent, check it to be before new extent. */ /* Found some extent, check it to be before new extent. */
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) { if ( ctx->al_entry->lowest_vcn == attr->lowest_vcn )
{
err = EEXIST; err = EEXIST;
ntfs_log_trace( "Such attribute already present in the " ntfs_log_trace( "Such attribute already present in the "
"attribute list.\n" ); "attribute list.\n" );
@ -165,9 +174,12 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
/* Add new entry after this extent. */ /* Add new entry after this extent. */
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry + ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
le16_to_cpu( ctx->al_entry->length ) ); le16_to_cpu( ctx->al_entry->length ) );
} else { }
else
{
/* Check for real errors. */ /* Check for real errors. */
if (errno != ENOENT) { if ( errno != ENOENT )
{
err = errno; err = errno;
ntfs_log_trace( "Attribute lookup failed.\n" ); ntfs_log_trace( "Attribute lookup failed.\n" );
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
@ -201,12 +213,14 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
/* Resize $ATTRIBUTE_LIST to new length. */ /* Resize $ATTRIBUTE_LIST to new length. */
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 ); na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
if (!na) { if ( !na )
{
err = errno; err = errno;
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" ); ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
goto err_out; goto err_out;
} }
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) { if ( ntfs_attr_truncate( na, ni->attr_list_size + entry_len ) )
{
err = errno; err = errno;
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" ); ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
goto err_out; goto err_out;
@ -250,7 +264,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
ATTR_LIST_ENTRY *ale; ATTR_LIST_ENTRY *ale;
int err; int err;
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) { if ( !ctx || !ctx->ntfs_ino || !ctx->al_entry )
{
ntfs_log_trace( "Invalid arguments.\n" ); ntfs_log_trace( "Invalid arguments.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -267,7 +282,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
( unsigned ) le32_to_cpu( ctx->al_entry->type ), ( unsigned ) le32_to_cpu( ctx->al_entry->type ),
( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) ); ( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) );
if (!NInoAttrList(base_ni)) { if ( !NInoAttrList( base_ni ) )
{
ntfs_log_trace( "Attribute list isn't present.\n" ); ntfs_log_trace( "Attribute list isn't present.\n" );
errno = ENOENT; errno = ENOENT;
return -1; return -1;
@ -281,12 +297,14 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
/* Reisze $ATTRIBUTE_LIST to new length. */ /* Reisze $ATTRIBUTE_LIST to new length. */
na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 ); na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
if (!na) { if ( !na )
{
err = errno; err = errno;
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" ); ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
goto err_out; goto err_out;
} }
if (ntfs_attr_truncate(na, new_al_len)) { if ( ntfs_attr_truncate( na, new_al_len ) )
{
err = errno; err = errno;
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" ); ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
goto err_out; goto err_out;

View File

@ -34,20 +34,24 @@
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
Functions to deal with little endian values stored in uint8_t arrays Functions to deal with little endian values stored in uint8_t arrays
-----------------------------------------------------------------*/ -----------------------------------------------------------------*/
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) { static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
{
return ( item[offset] | ( item[offset + 1] << 8 ) ); return ( item[offset] | ( item[offset + 1] << 8 ) );
} }
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) { static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
{
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) ); return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
} }
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) { static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
{
item[offset] = ( uint8_t ) value; item[offset] = ( uint8_t ) value;
item[offset + 1] = ( uint8_t )( value >> 8 ); item[offset + 1] = ( uint8_t )( value >> 8 );
} }
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) { static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
{
item[offset] = ( uint8_t ) value; item[offset] = ( uint8_t ) value;
item[offset + 1] = ( uint8_t )( value >> 8 ); item[offset + 1] = ( uint8_t )( value >> 8 );
item[offset + 2] = ( uint8_t )( value >> 16 ); item[offset + 2] = ( uint8_t )( value >> 16 );

View File

@ -119,7 +119,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
u8 *buf, *lastbyte_buf; u8 *buf, *lastbyte_buf;
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1; int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
if (!na || start_bit < 0 || count < 0) { if ( !na || start_bit < 0 || count < 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)", ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)",
__FUNCTION__, na, ( long long )start_bit, ( long long )count ); __FUNCTION__, na, ( long long )start_bit, ( long long )count );
@ -145,16 +146,19 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
memset( buf, value ? 0xff : 0, bufsize ); memset( buf, value ? 0xff : 0, bufsize );
/* If there is a first partial byte... */ /* If there is a first partial byte... */
if (bit) { if ( bit )
{
/* read it in... */ /* read it in... */
br = ntfs_attr_pread( na, start_bit >> 3, 1, buf ); br = ntfs_attr_pread( na, start_bit >> 3, 1, buf );
if (br != 1) { if ( br != 1 )
{
if ( br >= 0 ) if ( br >= 0 )
errno = EIO; errno = EIO;
goto free_err_out; goto free_err_out;
} }
/* and set or clear the appropriate bits in it. */ /* and set or clear the appropriate bits in it. */
while ((bit & 7) && count--) { while ( ( bit & 7 ) && count-- )
{
if ( value ) if ( value )
*buf |= 1 << bit++; *buf |= 1 << bit++;
else else
@ -168,11 +172,14 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
lastbyte = 0; lastbyte = 0;
lastbyte_buf = NULL; lastbyte_buf = NULL;
bit = count & 7; bit = count & 7;
do { do
{
/* If there is a last partial byte... */ /* If there is a last partial byte... */
if (count > 0 && bit) { if ( count > 0 && bit )
{
lastbyte_pos = ( ( count + 7 ) >> 3 ) + firstbyte; lastbyte_pos = ( ( count + 7 ) >> 3 ) + firstbyte;
if (!lastbyte_pos) { if ( !lastbyte_pos )
{
// FIXME: Eeek! BUG! // FIXME: Eeek! BUG!
ntfs_log_error( "Lastbyte is zero. Leaving " ntfs_log_error( "Lastbyte is zero. Leaving "
"inconsistent metadata.\n" ); "inconsistent metadata.\n" );
@ -180,13 +187,15 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
goto free_err_out; goto free_err_out;
} }
/* and it is in the currently loaded bitmap window... */ /* and it is in the currently loaded bitmap window... */
if (lastbyte_pos <= bufsize) { if ( lastbyte_pos <= bufsize )
{
lastbyte_buf = buf + lastbyte_pos - 1; lastbyte_buf = buf + lastbyte_pos - 1;
/* read the byte in... */ /* read the byte in... */
br = ntfs_attr_pread( na, ( start_bit + count ) >> br = ntfs_attr_pread( na, ( start_bit + count ) >>
3, 1, lastbyte_buf ); 3, 1, lastbyte_buf );
if (br != 1) { if ( br != 1 )
{
// FIXME: Eeek! We need rollback! (AIA) // FIXME: Eeek! We need rollback! (AIA)
if ( br >= 0 ) if ( br >= 0 )
errno = EIO; errno = EIO;
@ -196,7 +205,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
goto free_err_out; goto free_err_out;
} }
/* and set/clear the appropriate bits in it. */ /* and set/clear the appropriate bits in it. */
while (bit && count--) { while ( bit && count-- )
{
if ( value ) if ( value )
*lastbyte_buf |= 1 << --bit; *lastbyte_buf |= 1 << --bit;
else else
@ -212,7 +222,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
/* Write the prepared buffer to disk. */ /* Write the prepared buffer to disk. */
tmp = ( start_bit >> 3 ) - firstbyte; tmp = ( start_bit >> 3 ) - firstbyte;
br = ntfs_attr_pwrite( na, tmp, bufsize, buf ); br = ntfs_attr_pwrite( na, tmp, bufsize, buf );
if (br != bufsize) { if ( br != bufsize )
{
// FIXME: Eeek! We need rollback! (AIA) // FIXME: Eeek! We need rollback! (AIA)
if ( br >= 0 ) if ( br >= 0 )
errno = EIO; errno = EIO;
@ -224,7 +235,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
/* Update counters. */ /* Update counters. */
tmp = ( bufsize - firstbyte - lastbyte ) << 3; tmp = ( bufsize - firstbyte - lastbyte ) << 3;
if (firstbyte) { if ( firstbyte )
{
firstbyte = 0; firstbyte = 0;
/* /*
* Re-set the partial first byte so a subsequent write * Re-set the partial first byte so a subsequent write
@ -237,7 +249,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) ) if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) )
bufsize = tmp; bufsize = tmp;
if (lastbyte && count != 0) { if ( lastbyte && count != 0 )
{
// FIXME: Eeek! BUG! // FIXME: Eeek! BUG!
ntfs_log_error( "Last buffer but count is not zero " ntfs_log_error( "Last buffer but count is not zero "
"(%lld). Leaving inconsistent metadata.\n", "(%lld). Leaving inconsistent metadata.\n",
@ -245,7 +258,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
errno = EIO; errno = EIO;
goto free_err_out; goto free_err_out;
} }
} while (count > 0); }
while ( count > 0 );
ret = 0; ret = 0;

View File

@ -65,21 +65,24 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
ntfs_log_debug( "Beginning bootsector check.\n" ); ntfs_log_debug( "Beginning bootsector check.\n" );
ntfs_log_debug( "Checking OEMid, NTFS signature.\n" ); ntfs_log_debug( "Checking OEMid, NTFS signature.\n" );
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */ if ( b->oem_id != cpu_to_le64( 0x202020205346544eULL ) ) /* "NTFS " */
{
ntfs_log_error( "NTFS signature is missing.\n" ); ntfs_log_error( "NTFS signature is missing.\n" );
goto not_ntfs; goto not_ntfs;
} }
ntfs_log_debug( "Checking bytes per sector.\n" ); ntfs_log_debug( "Checking bytes per sector.\n" );
if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 || if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 ||
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) { le16_to_cpu( b->bpb.bytes_per_sector ) > 4096 )
{
ntfs_log_error( "Unexpected bytes per sector value (%d).\n", ntfs_log_error( "Unexpected bytes per sector value (%d).\n",
le16_to_cpu( b->bpb.bytes_per_sector ) ); le16_to_cpu( b->bpb.bytes_per_sector ) );
goto not_ntfs; goto not_ntfs;
} }
ntfs_log_debug( "Checking sectors per cluster.\n" ); ntfs_log_debug( "Checking sectors per cluster.\n" );
switch (b->bpb.sectors_per_cluster) { switch ( b->bpb.sectors_per_cluster )
{
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
break; break;
default: default:
@ -91,7 +94,8 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
ntfs_log_debug( "Checking cluster size.\n" ); ntfs_log_debug( "Checking cluster size.\n" );
i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) * i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) *
b->bpb.sectors_per_cluster; b->bpb.sectors_per_cluster;
if (i > 65536) { if ( i > 65536 )
{
ntfs_log_error( "Unexpected cluster size (%d).\n", i ); ntfs_log_error( "Unexpected cluster size (%d).\n", i );
goto not_ntfs; goto not_ntfs;
} }
@ -102,7 +106,8 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
le16_to_cpu( b->bpb.sectors ) || le16_to_cpu( b->bpb.sectors ) ||
le16_to_cpu( b->bpb.sectors_per_fat ) || le16_to_cpu( b->bpb.sectors_per_fat ) ||
le32_to_cpu( b->bpb.large_sectors ) || le32_to_cpu( b->bpb.large_sectors ) ||
b->bpb.fats) { b->bpb.fats )
{
ntfs_log_error( "Reserved fields aren't zero " ntfs_log_error( "Reserved fields aren't zero "
"(%d, %d, %d, %d, %d, %d).\n", "(%d, %d, %d, %d, %d, %d).\n",
le16_to_cpu( b->bpb.reserved_sectors ), le16_to_cpu( b->bpb.reserved_sectors ),
@ -116,8 +121,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
ntfs_log_debug( "Checking clusters per mft record.\n" ); ntfs_log_debug( "Checking clusters per mft record.\n" );
if ( ( u8 )b->clusters_per_mft_record < 0xe1 || if ( ( u8 )b->clusters_per_mft_record < 0xe1 ||
(u8)b->clusters_per_mft_record > 0xf7) { ( u8 )b->clusters_per_mft_record > 0xf7 )
switch (b->clusters_per_mft_record) { {
switch ( b->clusters_per_mft_record )
{
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40: case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
break; break;
default: default:
@ -129,8 +136,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
ntfs_log_debug( "Checking clusters per index block.\n" ); ntfs_log_debug( "Checking clusters per index block.\n" );
if ( ( u8 )b->clusters_per_index_record < 0xe1 || if ( ( u8 )b->clusters_per_index_record < 0xe1 ||
(u8)b->clusters_per_index_record > 0xf7) { ( u8 )b->clusters_per_index_record > 0xf7 )
switch (b->clusters_per_index_record) { {
switch ( b->clusters_per_index_record )
{
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40: case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
break; break;
default: default:
@ -188,7 +197,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
*/ */
sectors_per_cluster = bs->bpb.sectors_per_cluster; sectors_per_cluster = bs->bpb.sectors_per_cluster;
ntfs_log_debug( "SectorsPerCluster = 0x%x\n", sectors_per_cluster ); ntfs_log_debug( "SectorsPerCluster = 0x%x\n", sectors_per_cluster );
if (sectors_per_cluster & (sectors_per_cluster - 1)) { if ( sectors_per_cluster & ( sectors_per_cluster - 1 ) )
{
ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2." ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2."
"\n", sectors_per_cluster ); "\n", sectors_per_cluster );
return -1; return -1;
@ -196,13 +206,15 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
sectors = sle64_to_cpu( bs->number_of_sectors ); sectors = sle64_to_cpu( bs->number_of_sectors );
ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors ); ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors );
if (!sectors) { if ( !sectors )
{
ntfs_log_error( "Volume size is set to zero.\n" ); ntfs_log_error( "Volume size is set to zero.\n" );
return -1; return -1;
} }
if ( vol->dev->d_ops->seek( vol->dev, if ( vol->dev->d_ops->seek( vol->dev,
( sectors - 1 ) << vol->sector_size_bits, ( sectors - 1 ) << vol->sector_size_bits,
SEEK_SET) == -1) { SEEK_SET ) == -1 )
{
ntfs_log_perror( "Failed to read last sector (%lld)", ntfs_log_perror( "Failed to read last sector (%lld)",
( long long )sectors ); ( long long )sectors );
ntfs_log_error( "%s", last_sector_error ); ntfs_log_error( "%s", last_sector_error );
@ -216,7 +228,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
ntfs_log_debug( "MFT LCN = %lld\n", ( long long )vol->mft_lcn ); ntfs_log_debug( "MFT LCN = %lld\n", ( long long )vol->mft_lcn );
ntfs_log_debug( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn ); ntfs_log_debug( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn );
if ( vol->mft_lcn > vol->nr_clusters || if ( vol->mft_lcn > vol->nr_clusters ||
vol->mftmirr_lcn > vol->nr_clusters) { vol->mftmirr_lcn > vol->nr_clusters )
{
ntfs_log_error( "$MFT LCN (%lld) or $MFTMirr LCN (%lld) is " ntfs_log_error( "$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
"greater than the number of clusters (%lld).\n", "greater than the number of clusters (%lld).\n",
( long long )vol->mft_lcn, ( long long )vol->mftmirr_lcn, ( long long )vol->mft_lcn, ( long long )vol->mftmirr_lcn,
@ -225,7 +238,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
} }
vol->cluster_size = sectors_per_cluster * vol->sector_size; vol->cluster_size = sectors_per_cluster * vol->sector_size;
if (vol->cluster_size & (vol->cluster_size - 1)) { if ( vol->cluster_size & ( vol->cluster_size - 1 ) )
{
ntfs_log_error( "cluster_size (%d) is not a power of 2.\n", ntfs_log_error( "cluster_size (%d) is not a power of 2.\n",
vol->cluster_size ); vol->cluster_size );
return -1; return -1;
@ -250,7 +264,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
vol->mft_record_size = 1 << -c; vol->mft_record_size = 1 << -c;
else else
vol->mft_record_size = c << vol->cluster_size_bits; vol->mft_record_size = c << vol->cluster_size_bits;
if (vol->mft_record_size & (vol->mft_record_size - 1)) { if ( vol->mft_record_size & ( vol->mft_record_size - 1 ) )
{
ntfs_log_error( "mft_record_size (%d) is not a power of 2.\n", ntfs_log_error( "mft_record_size (%d) is not a power of 2.\n",
vol->mft_record_size ); vol->mft_record_size );
return -1; return -1;

View File

@ -67,12 +67,15 @@ static void inserthashindex(struct CACHE_HEADER *cache,
struct HASH_ENTRY *link; struct HASH_ENTRY *link;
struct HASH_ENTRY *first; struct HASH_ENTRY *first;
if (cache->dohash) { if ( cache->dohash )
{
h = cache->dohash( current ); h = cache->dohash( current );
if ((h >= 0) && (h < cache->max_hash)) { if ( ( h >= 0 ) && ( h < cache->max_hash ) )
{
/* get a free link and insert at top of hash list */ /* get a free link and insert at top of hash list */
link = cache->free_hash; link = cache->free_hash;
if (link) { if ( link )
{
cache->free_hash = link->next; cache->free_hash = link->next;
first = cache->first_hash[h]; first = cache->first_hash[h];
if ( first ) if ( first )
@ -81,13 +84,17 @@ static void inserthashindex(struct CACHE_HEADER *cache,
link->next = NULL; link->next = NULL;
link->entry = current; link->entry = current;
cache->first_hash[h] = link; cache->first_hash[h] = link;
} else { }
else
{
ntfs_log_error( "No more hash entries," ntfs_log_error( "No more hash entries,"
" cache %s hashing dropped\n", " cache %s hashing dropped\n",
cache->name ); cache->name );
cache->dohash = ( cache_hash )NULL; cache->dohash = ( cache_hash )NULL;
} }
} else { }
else
{
ntfs_log_error( "Illegal hash value," ntfs_log_error( "Illegal hash value,"
" cache %s hashing dropped\n", " cache %s hashing dropped\n",
cache->name ); cache->name );
@ -106,29 +113,37 @@ static void drophashindex(struct CACHE_HEADER *cache,
struct HASH_ENTRY *link; struct HASH_ENTRY *link;
struct HASH_ENTRY *previous; struct HASH_ENTRY *previous;
if (cache->dohash) { if ( cache->dohash )
if ((hash >= 0) && (hash < cache->max_hash)) { {
if ( ( hash >= 0 ) && ( hash < cache->max_hash ) )
{
/* find the link and unlink */ /* find the link and unlink */
link = cache->first_hash[hash]; link = cache->first_hash[hash];
previous = ( struct HASH_ENTRY* )NULL; previous = ( struct HASH_ENTRY* )NULL;
while (link && (link->entry != current)) { while ( link && ( link->entry != current ) )
{
previous = link; previous = link;
link = link->next; link = link->next;
} }
if (link) { if ( link )
{
if ( previous ) if ( previous )
previous->next = link->next; previous->next = link->next;
else else
cache->first_hash[hash] = link->next; cache->first_hash[hash] = link->next;
link->next = cache->free_hash; link->next = cache->free_hash;
cache->free_hash = link; cache->free_hash = link;
} else { }
else
{
ntfs_log_error( "Bad hash list," ntfs_log_error( "Bad hash list,"
" cache %s hashing dropped\n", " cache %s hashing dropped\n",
cache->name ); cache->name );
cache->dohash = ( cache_hash )NULL; cache->dohash = ( cache_hash )NULL;
} }
} else { }
else
{
ntfs_log_error( "Illegal hash value," ntfs_log_error( "Illegal hash value,"
" cache %s hashing dropped\n", " cache %s hashing dropped\n",
cache->name ); cache->name );
@ -153,8 +168,10 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
int h; int h;
current = ( struct CACHED_GENERIC* )NULL; current = ( struct CACHED_GENERIC* )NULL;
if (cache) { if ( cache )
if (cache->dohash) { {
if ( cache->dohash )
{
/* /*
* When possible, use the hash table to * When possible, use the hash table to
* locate the entry if present * locate the entry if present
@ -166,21 +183,25 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
if ( link ) if ( link )
current = link->entry; current = link->entry;
} }
if (!cache->dohash) { if ( !cache->dohash )
{
/* /*
* Search sequentially in LRU list if no hash table * Search sequentially in LRU list if no hash table
* or if hashing has just failed * or if hashing has just failed
*/ */
current = cache->most_recent_entry; current = cache->most_recent_entry;
while ( current while ( current
&& compare(current, wanted)) { && compare( current, wanted ) )
{
current = current->next; current = current->next;
} }
} }
if (current) { if ( current )
{
previous = current->previous; previous = current->previous;
cache->hits++; cache->hits++;
if (previous) { if ( previous )
{
/* /*
* found and not at head of list, unlink from current * found and not at head of list, unlink from current
* position and relink as head of list * position and relink as head of list
@ -219,8 +240,10 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
int h; int h;
current = ( struct CACHED_GENERIC* )NULL; current = ( struct CACHED_GENERIC* )NULL;
if (cache) { if ( cache )
if (cache->dohash) { {
if ( cache->dohash )
{
/* /*
* When possible, use the hash table to * When possible, use the hash table to
* find out whether the entry if present * find out whether the entry if present
@ -229,11 +252,13 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
link = cache->first_hash[h]; link = cache->first_hash[h];
while ( link && compare( link->entry, item ) ) while ( link && compare( link->entry, item ) )
link = link->next; link = link->next;
if (link) { if ( link )
{
current = link->entry; current = link->entry;
} }
} }
if (!cache->dohash) { if ( !cache->dohash )
{
/* /*
* Search sequentially in LRU list to locate the end, * Search sequentially in LRU list to locate the end,
* and find out whether the entry is already in list * and find out whether the entry is already in list
@ -242,12 +267,14 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
*/ */
current = cache->most_recent_entry; current = cache->most_recent_entry;
while ( current while ( current
&& compare(current, item)) { && compare( current, item ) )
{
current = current->next; current = current->next;
} }
} }
if (!current) { if ( !current )
{
/* /*
* Not in list, get a free entry or reuse the * Not in list, get a free entry or reuse the
* last entry, and relink as head of list * last entry, and relink as head of list
@ -256,18 +283,23 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
* an entry is reused. * an entry is reused.
*/ */
if (cache->free_entry) { if ( cache->free_entry )
{
current = cache->free_entry; current = cache->free_entry;
cache->free_entry = cache->free_entry->next; cache->free_entry = cache->free_entry->next;
if (item->varsize) { if ( item->varsize )
{
current->variable = ntfs_malloc( current->variable = ntfs_malloc(
item->varsize ); item->varsize );
} else }
else
current->variable = ( void* )NULL; current->variable = ( void* )NULL;
current->varsize = item->varsize; current->varsize = item->varsize;
if ( !cache->oldest_entry ) if ( !cache->oldest_entry )
cache->oldest_entry = current; cache->oldest_entry = current;
} else { }
else
{
/* reusing the oldest entry */ /* reusing the oldest entry */
current = cache->oldest_entry; current = cache->oldest_entry;
before = current->previous; before = current->previous;
@ -278,7 +310,8 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
if ( cache->dofree ) if ( cache->dofree )
cache->dofree( current ); cache->dofree( current );
cache->oldest_entry = current->previous; cache->oldest_entry = current->previous;
if (item->varsize) { if ( item->varsize )
{
if ( current->varsize ) if ( current->varsize )
current->variable = realloc( current->variable = realloc(
current->variable, current->variable,
@ -286,7 +319,9 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
else else
current->variable = ntfs_malloc( current->variable = ntfs_malloc(
item->varsize ); item->varsize );
} else { }
else
{
if ( current->varsize ) if ( current->varsize )
free( current->variable ); free( current->variable );
current->variable = ( void* )NULL; current->variable = ( void* )NULL;
@ -299,11 +334,15 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
cache->most_recent_entry->previous = current; cache->most_recent_entry->previous = current;
cache->most_recent_entry = current; cache->most_recent_entry = current;
memcpy( current->fixed, item->fixed, cache->fixed_size ); memcpy( current->fixed, item->fixed, cache->fixed_size );
if (item->varsize) { if ( item->varsize )
if (current->variable) { {
if ( current->variable )
{
memcpy( current->variable, memcpy( current->variable,
item->variable, item->varsize ); item->variable, item->varsize );
} else { }
else
{
/* /*
* no more memory for variable part * no more memory for variable part
* recycle entry in free list * recycle entry in free list
@ -314,7 +353,9 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
cache->free_entry = current; cache->free_entry = current;
current = ( struct CACHED_GENERIC* )NULL; current = ( struct CACHED_GENERIC* )NULL;
} }
} else { }
else
{
current->variable = ( void* )NULL; current->variable = ( void* )NULL;
current->varsize = 0; current->varsize = 0;
} }
@ -384,21 +425,26 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
current = ( struct CACHED_GENERIC* )NULL; current = ( struct CACHED_GENERIC* )NULL;
count = 0; count = 0;
if (cache) { if ( cache )
if (!(flags & CACHE_NOHASH) && cache->dohash) { {
if ( !( flags & CACHE_NOHASH ) && cache->dohash )
{
/* /*
* When possible, use the hash table to * When possible, use the hash table to
* find out whether the entry if present * find out whether the entry if present
*/ */
h = cache->dohash( item ); h = cache->dohash( item );
link = cache->first_hash[h]; link = cache->first_hash[h];
while (link) { while ( link )
{
if ( compare( link->entry, item ) ) if ( compare( link->entry, item ) )
link = link->next; link = link->next;
else { else
{
current = link->entry; current = link->entry;
link = link->next; link = link->next;
if (current) { if ( current )
{
drophashindex( cache, current, h ); drophashindex( cache, current, h );
do_invalidate( cache, do_invalidate( cache,
current, flags ); current, flags );
@ -407,14 +453,17 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
} }
} }
} }
if ((flags & CACHE_NOHASH) || !cache->dohash) { if ( ( flags & CACHE_NOHASH ) || !cache->dohash )
{
/* /*
* Search sequentially in LRU list * Search sequentially in LRU list
*/ */
current = cache->most_recent_entry; current = cache->most_recent_entry;
previous = ( struct CACHED_GENERIC* )NULL; previous = ( struct CACHED_GENERIC* )NULL;
while (current) { while ( current )
if (!compare(current, item)) { {
if ( !compare( current, item ) )
{
next = current->next; next = current->next;
if ( cache->dohash ) if ( cache->dohash )
drophashindex( cache, current, drophashindex( cache, current,
@ -422,7 +471,9 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
do_invalidate( cache, current, flags ); do_invalidate( cache, current, flags );
current = next; current = next;
count++; count++;
} else { }
else
{
previous = current; previous = current;
current = current->next; current = current->next;
} }
@ -438,7 +489,8 @@ int ntfs_remove_cache(struct CACHE_HEADER *cache,
int count; int count;
count = 0; count = 0;
if (cache) { if ( cache )
{
if ( cache->dohash ) if ( cache->dohash )
drophashindex( cache, item, cache->dohash( item ) ); drophashindex( cache, item, cache->dohash( item ) );
do_invalidate( cache, item, flags ); do_invalidate( cache, item, flags );
@ -455,8 +507,10 @@ static void ntfs_free_cache(struct CACHE_HEADER *cache)
{ {
struct CACHED_GENERIC *entry; struct CACHED_GENERIC *entry;
if (cache) { if ( cache )
for (entry=cache->most_recent_entry; entry; entry=entry->next) { {
for ( entry = cache->most_recent_entry; entry; entry = entry->next )
{
if ( cache->dofree ) if ( cache->dofree )
cache->dofree( entry ); cache->dofree( entry );
if ( entry->variable ) if ( entry->variable )
@ -491,14 +545,18 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
size += item_count*sizeof( struct HASH_ENTRY ) size += item_count*sizeof( struct HASH_ENTRY )
+ max_hash*sizeof( struct HASH_ENTRY* ); + max_hash*sizeof( struct HASH_ENTRY* );
cache = ( struct CACHE_HEADER* )ntfs_malloc( size ); cache = ( struct CACHE_HEADER* )ntfs_malloc( size );
if (cache) { if ( cache )
{
/* header */ /* header */
cache->name = name; cache->name = name;
cache->dofree = dofree; cache->dofree = dofree;
if (dohash && max_hash) { if ( dohash && max_hash )
{
cache->dohash = dohash; cache->dohash = dohash;
cache->max_hash = max_hash; cache->max_hash = max_hash;
} else { }
else
{
cache->dohash = ( cache_hash )NULL; cache->dohash = ( cache_hash )NULL;
cache->max_hash = 0; cache->max_hash = 0;
} }
@ -511,7 +569,8 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
cache->oldest_entry = ( struct CACHED_GENERIC* )NULL; cache->oldest_entry = ( struct CACHED_GENERIC* )NULL;
cache->free_entry = &cache->entry[0]; cache->free_entry = &cache->entry[0];
pc = &cache->entry[0]; pc = &cache->entry[0];
for (i=0; i<(item_count - 1); i++) { for ( i = 0; i < ( item_count - 1 ); i++ )
{
qc = ( struct CACHED_GENERIC* )( ( char* )pc qc = ( struct CACHED_GENERIC* )( ( char* )pc
+ full_item_size ); + full_item_size );
pc->next = qc; pc->next = qc;
@ -524,17 +583,20 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
pc->variable = ( void* )NULL; pc->variable = ( void* )NULL;
pc->varsize = 0; pc->varsize = 0;
if (max_hash) { if ( max_hash )
{
/* chain the hash entries */ /* chain the hash entries */
ph = ( struct HASH_ENTRY* )( ( ( char* )pc ) + full_item_size ); ph = ( struct HASH_ENTRY* )( ( ( char* )pc ) + full_item_size );
cache->free_hash = ph; cache->free_hash = ph;
for (i=0; i<(item_count - 1); i++) { for ( i = 0; i < ( item_count - 1 ); i++ )
{
qh = &ph[1]; qh = &ph[1];
ph->next = qh; ph->next = qh;
ph = qh; ph = qh;
} }
/* special for the last entry */ /* special for the last entry */
if (item_count) { if ( item_count )
{
ph->next = ( struct HASH_ENTRY* )NULL; ph->next = ( struct HASH_ENTRY* )NULL;
} }
/* create and initialize the hash indexes */ /* create and initialize the hash indexes */
@ -542,7 +604,9 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
cache->first_hash = px; cache->first_hash = px;
for ( i = 0; i < max_hash; i++ ) for ( i = 0; i < max_hash; i++ )
px[i] = ( struct HASH_ENTRY* )NULL; px[i] = ( struct HASH_ENTRY* )NULL;
} else { }
else
{
cache->free_hash = ( struct HASH_ENTRY* )NULL; cache->free_hash = ( struct HASH_ENTRY* )NULL;
cache->first_hash = ( struct HASH_ENTRY** )NULL; cache->first_hash = ( struct HASH_ENTRY** )NULL;
} }

View File

@ -24,19 +24,22 @@
#include "volume.h" #include "volume.h"
struct CACHED_GENERIC { struct CACHED_GENERIC
{
struct CACHED_GENERIC *next; struct CACHED_GENERIC *next;
struct CACHED_GENERIC *previous; struct CACHED_GENERIC *previous;
void *variable; void *variable;
size_t varsize; size_t varsize;
union { union
{
/* force alignment for pointers and u64 */ /* force alignment for pointers and u64 */
u64 u64align; u64 u64align;
void *ptralign; void *ptralign;
} fixed[0]; } fixed[0];
} ; } ;
struct CACHED_INODE { struct CACHED_INODE
{
struct CACHED_INODE *next; struct CACHED_INODE *next;
struct CACHED_INODE *previous; struct CACHED_INODE *previous;
const char *pathname; const char *pathname;
@ -45,7 +48,8 @@ struct CACHED_INODE {
u64 inum; u64 inum;
} ; } ;
struct CACHED_NIDATA { struct CACHED_NIDATA
{
struct CACHED_NIDATA *next; struct CACHED_NIDATA *next;
struct CACHED_NIDATA *previous; struct CACHED_NIDATA *previous;
const char *pathname; /* not used */ const char *pathname; /* not used */
@ -55,7 +59,8 @@ struct CACHED_NIDATA {
ntfs_inode *ni; ntfs_inode *ni;
} ; } ;
struct CACHED_LOOKUP { struct CACHED_LOOKUP
{
struct CACHED_LOOKUP *next; struct CACHED_LOOKUP *next;
struct CACHED_LOOKUP *previous; struct CACHED_LOOKUP *previous;
const char *name; const char *name;
@ -65,7 +70,8 @@ struct CACHED_LOOKUP {
u64 inum; u64 inum;
} ; } ;
enum { enum
{
CACHE_FREE = 1, CACHE_FREE = 1,
CACHE_NOHASH = 2 CACHE_NOHASH = 2
} ; } ;
@ -75,12 +81,14 @@ typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
typedef void ( *cache_free )( const struct CACHED_GENERIC *cached ); typedef void ( *cache_free )( const struct CACHED_GENERIC *cached );
typedef int ( *cache_hash )( const struct CACHED_GENERIC *cached ); typedef int ( *cache_hash )( const struct CACHED_GENERIC *cached );
struct HASH_ENTRY { struct HASH_ENTRY
{
struct HASH_ENTRY *next; struct HASH_ENTRY *next;
struct CACHED_GENERIC *entry; struct CACHED_GENERIC *entry;
} ; } ;
struct CACHE_HEADER { struct CACHE_HEADER
{
const char *name; const char *name;
struct CACHED_GENERIC *most_recent_entry; struct CACHED_GENERIC *most_recent_entry;
struct CACHED_GENERIC *oldest_entry; struct CACHED_GENERIC *oldest_entry;

View File

@ -45,23 +45,27 @@
#define CACHE_FREE UINT_MAX #define CACHE_FREE UINT_MAX
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize) { NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize )
{
NTFS_CACHE* cache; NTFS_CACHE* cache;
unsigned int i; unsigned int i;
NTFS_CACHE_ENTRY* cacheEntries; NTFS_CACHE_ENTRY* cacheEntries;
if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL; if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL;
if (numberOfPages < 4) { if ( numberOfPages < 4 )
{
numberOfPages = 4; numberOfPages = 4;
} }
if (sectorsPerPage < 32) { if ( sectorsPerPage < 32 )
{
sectorsPerPage = 32; sectorsPerPage = 32;
} }
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) ); cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
if (cache == NULL) { if ( cache == NULL )
{
return NULL; return NULL;
} }
@ -73,12 +77,14 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
cacheEntries = ( NTFS_CACHE_ENTRY* ) ntfs_alloc ( sizeof( NTFS_CACHE_ENTRY ) * numberOfPages ); cacheEntries = ( NTFS_CACHE_ENTRY* ) ntfs_alloc ( sizeof( NTFS_CACHE_ENTRY ) * numberOfPages );
if (cacheEntries == NULL) { if ( cacheEntries == NULL )
{
ntfs_free ( cache ); ntfs_free ( cache );
return NULL; return NULL;
} }
for (i = 0; i < numberOfPages; i++) { for ( i = 0; i < numberOfPages; i++ )
{
cacheEntries[i].sector = CACHE_FREE; cacheEntries[i].sector = CACHE_FREE;
cacheEntries[i].count = 0; cacheEntries[i].count = 0;
cacheEntries[i].last_access = 0; cacheEntries[i].last_access = 0;
@ -91,7 +97,8 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
return cache; return cache;
} }
void _NTFS_cache_destructor (NTFS_CACHE* cache) { void _NTFS_cache_destructor ( NTFS_CACHE* cache )
{
unsigned int i; unsigned int i;
if ( cache == NULL ) return; if ( cache == NULL ) return;
@ -100,7 +107,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
_NTFS_cache_flush( cache ); _NTFS_cache_flush( cache );
// Free memory in reverse allocation order // Free memory in reverse allocation order
for (i = 0; i < cache->numberOfPages; i++) { for ( i = 0; i < cache->numberOfPages; i++ )
{
ntfs_free ( cache->cacheEntries[i].cache ); ntfs_free ( cache->cacheEntries[i].cache );
} }
ntfs_free ( cache->cacheEntries ); ntfs_free ( cache->cacheEntries );
@ -109,7 +117,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
static u32 accessCounter = 0; static u32 accessCounter = 0;
static u32 accessTime(){ static u32 accessTime()
{
accessCounter++; accessCounter++;
return accessCounter; return accessCounter;
} }
@ -125,20 +134,24 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
unsigned int oldUsed = 0; unsigned int oldUsed = 0;
unsigned int oldAccess = UINT_MAX; unsigned int oldAccess = UINT_MAX;
for(i=0;i<numberOfPages;i++) { for ( i = 0; i < numberOfPages; i++ )
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) { {
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
{
cacheEntries[i].last_access = accessTime(); cacheEntries[i].last_access = accessTime();
return &( cacheEntries[i] ); return &( cacheEntries[i] );
} }
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) { if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
{
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true; if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
oldUsed = i; oldUsed = i;
oldAccess = cacheEntries[i].last_access; oldAccess = cacheEntries[i].last_access;
} }
} }
if(foundFree==false && cacheEntries[oldUsed].dirty==true) { if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
{
if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL; if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
cacheEntries[oldUsed].dirty = false; cacheEntries[oldUsed].dirty = false;
} }
@ -155,7 +168,8 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
return &( cacheEntries[oldUsed] ); return &( cacheEntries[oldUsed] );
} }
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) { static NTFS_CACHE_ENTRY* _NTFS_cache_findPage( NTFS_CACHE *cache, sec_t sector, sec_t count )
{
unsigned int i; unsigned int i;
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries; NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
@ -163,16 +177,22 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
NTFS_CACHE_ENTRY *entry = NULL; NTFS_CACHE_ENTRY *entry = NULL;
sec_t lowest = UINT_MAX; sec_t lowest = UINT_MAX;
for(i=0;i<numberOfPages;i++) { for ( i = 0; i < numberOfPages; i++ )
if (cacheEntries[i].sector != CACHE_FREE) { {
if ( cacheEntries[i].sector != CACHE_FREE )
{
bool intersect; bool intersect;
if (sector > cacheEntries[i].sector) { if ( sector > cacheEntries[i].sector )
{
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count; intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
} else { }
else
{
intersect = cacheEntries[i].sector - sector < count; intersect = cacheEntries[i].sector - sector < count;
} }
if ( intersect && (cacheEntries[i].sector < lowest)) { if ( intersect && ( cacheEntries[i].sector < lowest ) )
{
lowest = cacheEntries[i].sector; lowest = cacheEntries[i].sector;
entry = &cacheEntries[i]; entry = &cacheEntries[i];
} }
@ -189,7 +209,8 @@ bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,voi
NTFS_CACHE_ENTRY *entry; NTFS_CACHE_ENTRY *entry;
uint8_t *dest = buffer; uint8_t *dest = buffer;
while(numSectors>0) { while ( numSectors > 0 )
{
entry = _NTFS_cache_getPage( cache, sector ); entry = _NTFS_cache_getPage( cache, sector );
if ( entry == NULL ) return false; if ( entry == NULL ) return false;
@ -227,11 +248,13 @@ bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t secto
return true; return true;
} }
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) { bool _NTFS_cache_readLittleEndianValue ( NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
{
uint8_t buf[4]; uint8_t buf[4];
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false; if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
switch(num_bytes) { switch ( num_bytes )
{
case 1: *value = buf[0]; break; case 1: *value = buf[0]; break;
case 2: *value = u8array_to_u16( buf, 0 ); break; case 2: *value = u8array_to_u16( buf, 0 ); break;
case 4: *value = u8array_to_u32( buf, 0 ); break; case 4: *value = u8array_to_u32( buf, 0 ); break;
@ -261,10 +284,12 @@ bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_
return true; return true;
} }
bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) { bool _NTFS_cache_writeLittleEndianValue ( NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
{
uint8_t buf[4] = {0, 0, 0, 0}; uint8_t buf[4] = {0, 0, 0, 0};
switch(size) { switch ( size )
{
case 1: buf[0] = value; break; case 1: buf[0] = value; break;
case 2: u16_to_u8array( buf, 0, value ); break; case 2: u16_to_u8array( buf, 0, value ); break;
case 4: u32_to_u8array( buf, 0, value ); break; case 4: u32_to_u8array( buf, 0, value ); break;
@ -307,9 +332,11 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
{ {
entry = _NTFS_cache_findPage( cache, sector, numSectors ); entry = _NTFS_cache_findPage( cache, sector, numSectors );
if(entry!=NULL) { if ( entry != NULL )
{
if ( entry->sector > sector) { if ( entry->sector > sector )
{
secs_to_write = entry->sector - sector; secs_to_write = entry->sector - sector;
@ -332,7 +359,9 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
entry->dirty = true; entry->dirty = true;
} else { }
else
{
cache->disc->writeSectors( sector, numSectors, src ); cache->disc->writeSectors( sector, numSectors, src );
numSectors = 0; numSectors = 0;
} }
@ -343,13 +372,17 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
/* /*
Flushes all dirty pages to disc, clearing the dirty flag. Flushes all dirty pages to disc, clearing the dirty flag.
*/ */
bool _NTFS_cache_flush (NTFS_CACHE* cache) { bool _NTFS_cache_flush ( NTFS_CACHE* cache )
{
unsigned int i; unsigned int i;
if ( cache == NULL ) return true; if ( cache == NULL ) return true;
for (i = 0; i < cache->numberOfPages; i++) { for ( i = 0; i < cache->numberOfPages; i++ )
if (cache->cacheEntries[i].dirty) { {
if (!cache->disc->writeSectors (cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) { if ( cache->cacheEntries[i].dirty )
{
if ( !cache->disc->writeSectors ( cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
{
return false; return false;
} }
} }
@ -359,13 +392,15 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
return true; return true;
} }
void _NTFS_cache_invalidate (NTFS_CACHE* cache) { void _NTFS_cache_invalidate ( NTFS_CACHE* cache )
{
unsigned int i; unsigned int i;
if ( cache == NULL ) if ( cache == NULL )
return; return;
_NTFS_cache_flush( cache ); _NTFS_cache_flush( cache );
for (i = 0; i < cache->numberOfPages; i++) { for ( i = 0; i < cache->numberOfPages; i++ )
{
cache->cacheEntries[i].sector = CACHE_FREE; cache->cacheEntries[i].sector = CACHE_FREE;
cache->cacheEntries[i].last_access = 0; cache->cacheEntries[i].last_access = 0;
cache->cacheEntries[i].count = 0; cache->cacheEntries[i].count = 0;

View File

@ -46,7 +46,8 @@
#include <ogc/disc_io.h> #include <ogc/disc_io.h>
#include <gccore.h> #include <gccore.h>
typedef struct { typedef struct
{
sec_t sector; sec_t sector;
unsigned int count; unsigned int count;
u64 last_access; u64 last_access;
@ -54,7 +55,8 @@ typedef struct {
u8* cache; u8* cache;
} NTFS_CACHE_ENTRY; } NTFS_CACHE_ENTRY;
typedef struct { typedef struct
{
const DISC_INTERFACE* disc; const DISC_INTERFACE* disc;
sec_t endOfPartition; sec_t endOfPartition;
unsigned int numberOfPages; unsigned int numberOfPages;

View File

@ -60,7 +60,8 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
ntfs_log_trace( "Entering.\n" ); ntfs_log_trace( "Entering.\n" );
rc = memcmp( data1, data2, min( data1_len, data2_len ) ); rc = memcmp( data1, data2, min( data1_len, data2_len ) );
if (!rc && (data1_len != data2_len)) { if ( !rc && ( data1_len != data2_len ) )
{
if ( data1_len < data2_len ) if ( data1_len < data2_len )
rc = -1; rc = -1;
else else
@ -90,7 +91,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
u32 d1, d2; u32 d1, d2;
ntfs_log_trace( "Entering.\n" ); ntfs_log_trace( "Entering.\n" );
if (data1_len != data2_len || data1_len != 4) { if ( data1_len != data2_len || data1_len != 4 )
{
ntfs_log_error( "data1_len or/and data2_len not equal to 4.\n" ); ntfs_log_error( "data1_len or/and data2_len not equal to 4.\n" );
return NTFS_COLLATION_ERROR; return NTFS_COLLATION_ERROR;
} }
@ -98,7 +100,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
d2 = le32_to_cpup( data2 ); d2 = le32_to_cpup( data2 );
if ( d1 < d2 ) if ( d1 < d2 )
rc = -1; rc = -1;
else { else
{
if ( d1 == d2 ) if ( d1 == d2 )
rc = 0; rc = 0;
else else
@ -124,22 +127,26 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
u32 d1, d2; u32 d1, d2;
ntfs_log_trace( "Entering.\n" ); ntfs_log_trace( "Entering.\n" );
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) { if ( ( data1_len != data2_len ) || ( data1_len <= 0 ) || ( data1_len & 3 ) )
{
ntfs_log_error( "data1_len or data2_len not valid\n" ); ntfs_log_error( "data1_len or data2_len not valid\n" );
return NTFS_COLLATION_ERROR; return NTFS_COLLATION_ERROR;
} }
p1 = ( const le32* )data1; p1 = ( const le32* )data1;
p2 = ( const le32* )data2; p2 = ( const le32* )data2;
len = data1_len; len = data1_len;
do { do
{
d1 = le32_to_cpup( p1 ); d1 = le32_to_cpup( p1 );
p1++; p1++;
d2 = le32_to_cpup( p2 ); d2 = le32_to_cpup( p2 );
p2++; p2++;
} while ((d1 == d2) && ((len -= 4) > 0)); }
while ( ( d1 == d2 ) && ( ( len -= 4 ) > 0 ) );
if ( d1 < d2 ) if ( d1 < d2 )
rc = -1; rc = -1;
else { else
{
if ( d1 == d2 ) if ( d1 == d2 )
rc = 0; rc = 0;
else else
@ -171,7 +178,8 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
const le32 *p1, *p2; const le32 *p1, *p2;
ntfs_log_trace( "Entering.\n" ); ntfs_log_trace( "Entering.\n" );
if (data1_len != data2_len || data1_len != 8) { if ( data1_len != data2_len || data1_len != 8 )
{
ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" ); ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" );
return NTFS_COLLATION_ERROR; return NTFS_COLLATION_ERROR;
} }
@ -181,17 +189,20 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
d2 = le32_to_cpup( p2 ); d2 = le32_to_cpup( p2 );
if ( d1 < d2 ) if ( d1 < d2 )
rc = -1; rc = -1;
else { else
{
if ( d1 > d2 ) if ( d1 > d2 )
rc = 1; rc = 1;
else { else
{
p1++; p1++;
p2++; p2++;
d1 = le32_to_cpup( p1 ); d1 = le32_to_cpup( p1 );
d2 = le32_to_cpup( p2 ); d2 = le32_to_cpup( p2 );
if ( d1 < d2 ) if ( d1 < d2 )
rc = -1; rc = -1;
else { else
{
if ( d1 > d2 ) if ( d1 > d2 )
rc = 1; rc = 1;
else else
@ -246,7 +257,8 @@ COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
{ {
COLLATE collate; COLLATE collate;
switch (cr) { switch ( cr )
{
case COLLATION_BINARY : case COLLATION_BINARY :
collate = ntfs_collate_binary; collate = ntfs_collate_binary;
break; break;

View File

@ -41,23 +41,28 @@ int ffs(int x)
if ( !x ) if ( !x )
return 0; return 0;
if (!(x & 0xffff)) { if ( !( x & 0xffff ) )
{
x >>= 16; x >>= 16;
r += 16; r += 16;
} }
if (!(x & 0xff)) { if ( !( x & 0xff ) )
{
x >>= 8; x >>= 8;
r += 8; r += 8;
} }
if (!(x & 0xf)) { if ( !( x & 0xf ) )
{
x >>= 4; x >>= 4;
r += 4; r += 4;
} }
if (!(x & 3)) { if ( !( x & 3 ) )
{
x >>= 2; x >>= 2;
r += 2; r += 2;
} }
if (!(x & 1)) { if ( !( x & 1 ) )
{
x >>= 1; x >>= 1;
r += 1; r += 1;
} }
@ -120,10 +125,12 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
#include <unistd.h> #include <unistd.h>
#endif #endif
int daemon(int nochdir, int noclose) { int daemon( int nochdir, int noclose )
{
int fd; int fd;
switch (fork()) { switch ( fork() )
{
case -1: case -1:
return ( -1 ); return ( -1 );
case 0: case 0:
@ -138,7 +145,8 @@ int daemon(int nochdir, int noclose) {
if ( !nochdir ) if ( !nochdir )
( void )chdir( "/" ); ( void )chdir( "/" );
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { if ( !noclose && ( fd = open( "/dev/null", O_RDWR, 0 ) ) != -1 )
{
( void )dup2( fd, 0 ); ( void )dup2( fd, 0 );
( void )dup2( fd, 1 ); ( void )dup2( fd, 1 );
( void )dup2( fd, 2 ); ( void )dup2( fd, 2 );
@ -218,7 +226,8 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
* *
* If *stringp is NULL, strsep returns NULL. * If *stringp is NULL, strsep returns NULL.
*/ */
char *strsep(char **stringp, const char *delim) { char *strsep( char **stringp, const char *delim )
{
char *s; char *s;
const char *spanp; const char *spanp;
int c, sc; int c, sc;
@ -226,11 +235,14 @@ char *strsep(char **stringp, const char *delim) {
if ( ( s = *stringp ) == NULL ) if ( ( s = *stringp ) == NULL )
return ( NULL ); return ( NULL );
for (tok = s;;) { for ( tok = s;; )
{
c = *s++; c = *s++;
spanp = delim; spanp = delim;
do { do
if ((sc = *spanp++) == c) { {
if ( ( sc = *spanp++ ) == c )
{
if ( c == 0 ) if ( c == 0 )
s = NULL; s = NULL;
else else
@ -238,7 +250,8 @@ char *strsep(char **stringp, const char *delim) {
*stringp = s; *stringp = s;
return ( tok ); return ( tok );
} }
} while (sc != 0); }
while ( sc != 0 );
} }
/* NOTREACHED */ /* NOTREACHED */
} }

File diff suppressed because it is too large Load Diff

View File

@ -47,18 +47,22 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
int i = 0; int i = 0;
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED", const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
"LCN_ENOENT ", "LCN_EINVAL ", "LCN_ENOENT ", "LCN_EINVAL ",
"LCN_unknown " }; "LCN_unknown "
};
ntfs_log_debug( "NTFS-fs DEBUG: Dumping runlist (values in hex):\n" ); ntfs_log_debug( "NTFS-fs DEBUG: Dumping runlist (values in hex):\n" );
if (!rl) { if ( !rl )
{
ntfs_log_debug( "Run list not present.\n" ); ntfs_log_debug( "Run list not present.\n" );
return; return;
} }
ntfs_log_debug( "VCN LCN Run length\n" ); ntfs_log_debug( "VCN LCN Run length\n" );
do { do
{
LCN lcn = ( rl + i )->lcn; LCN lcn = ( rl + i )->lcn;
if (lcn < (LCN)0) { if ( lcn < ( LCN )0 )
{
int idx = -lcn - 1; int idx = -lcn - 1;
if ( idx > -LCN_EINVAL - 1 ) if ( idx > -LCN_EINVAL - 1 )
@ -67,12 +71,14 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
( long long )rl[i].vcn, lcn_str[idx], ( long long )rl[i].vcn, lcn_str[idx],
( long long )rl[i].length, ( long long )rl[i].length,
rl[i].length ? "" : " (runlist end)" ); rl[i].length ? "" : " (runlist end)" );
} else }
else
ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n", ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n",
( long long )rl[i].vcn, ( long long )rl[i].lcn, ( long long )rl[i].vcn, ( long long )rl[i].lcn,
( long long )rl[i].length, ( long long )rl[i].length,
rl[i].length ? "" : " (runlist end)" ); rl[i].length ? "" : " (runlist end)" );
} while (rl[i++].length); }
while ( rl[i++].length );
} }
#endif #endif

View File

@ -108,14 +108,17 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
{ {
struct ntfs_device *dev; struct ntfs_device *dev;
if (!name) { if ( !name )
{
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
dev = ntfs_malloc( sizeof( struct ntfs_device ) ); dev = ntfs_malloc( sizeof( struct ntfs_device ) );
if (dev) { if ( dev )
if (!(dev->d_name = strdup(name))) { {
if ( !( dev->d_name = strdup( name ) ) )
{
int eo = errno; int eo = errno;
free( dev ); free( dev );
errno = eo; errno = eo;
@ -141,11 +144,13 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
*/ */
int ntfs_device_free( struct ntfs_device *dev ) int ntfs_device_free( struct ntfs_device *dev )
{ {
if (!dev) { if ( !dev )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (NDevOpen(dev)) { if ( NDevOpen( dev ) )
{
errno = EBUSY; errno = EBUSY;
return -1; return -1;
} }
@ -180,7 +185,8 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count ); ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
if (!b || count < 0 || pos < 0) { if ( !b || count < 0 || pos < 0 )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -189,7 +195,8 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
dops = dev->d_ops; dops = dev->d_ops;
for (total = 0; count; count -= br, total += br) { for ( total = 0; count; count -= br, total += br )
{
br = dops->pread( dev, ( char* )b + total, count, pos + total ); br = dops->pread( dev, ( char* )b + total, count, pos + total );
/* If everything ok, continue. */ /* If everything ok, continue. */
if ( br > 0 ) if ( br > 0 )
@ -231,13 +238,15 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count ); ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
if (!b || count < 0 || pos < 0) { if ( !b || count < 0 || pos < 0 )
{
errno = EINVAL; errno = EINVAL;
goto out; goto out;
} }
if ( !count ) if ( !count )
return 0; return 0;
if (NDevReadOnly(dev)) { if ( NDevReadOnly( dev ) )
{
errno = EROFS; errno = EROFS;
goto out; goto out;
} }
@ -245,7 +254,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
dops = dev->d_ops; dops = dev->d_ops;
NDevSetDirty( dev ); NDevSetDirty( dev );
for (total = 0; count; count -= written, total += written) { for ( total = 0; count; count -= written, total += written )
{
written = dops->pwrite( dev, ( const char* )b + total, count, written = dops->pwrite( dev, ( const char* )b + total, count,
pos + total ); pos + total );
/* If everything ok, continue. */ /* If everything ok, continue. */
@ -299,7 +309,8 @@ s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
{ {
s64 br, i; s64 br, i;
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) { if ( bksize & ( bksize - 1 ) || bksize % NTFS_BLOCK_SIZE )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -356,19 +367,22 @@ s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
{ {
s64 written, i; s64 written, i;
if (count < 0 || bksize % NTFS_BLOCK_SIZE) { if ( count < 0 || bksize % NTFS_BLOCK_SIZE )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if ( !count ) if ( !count )
return 0; return 0;
/* Prepare data for writing. */ /* Prepare data for writing. */
for (i = 0; i < count; ++i) { for ( i = 0; i < count; ++i )
{
int err; int err;
err = ntfs_mst_pre_write_fixup( ( NTFS_RECORD* ) err = ntfs_mst_pre_write_fixup( ( NTFS_RECORD* )
( ( u8* )b + i * bksize ), bksize ); ( ( u8* )b + i * bksize ), bksize );
if (err < 0) { if ( err < 0 )
{
/* Abort write at this position. */ /* Abort write at this position. */
if ( !i ) if ( !i )
return err; return err;
@ -403,11 +417,13 @@ s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
{ {
s64 br; s64 br;
if (!vol || lcn < 0 || count < 0) { if ( !vol || lcn < 0 || count < 0 )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (vol->nr_clusters < lcn + count) { if ( vol->nr_clusters < lcn + count )
{
errno = ESPIPE; errno = ESPIPE;
ntfs_log_perror( "Trying to read outside of volume " ntfs_log_perror( "Trying to read outside of volume "
"(%lld < %lld)", ( long long )vol->nr_clusters, "(%lld < %lld)", ( long long )vol->nr_clusters,
@ -416,7 +432,8 @@ s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
} }
br = ntfs_pread( vol->dev, lcn << vol->cluster_size_bits, br = ntfs_pread( vol->dev, lcn << vol->cluster_size_bits,
count << vol->cluster_size_bits, b ); count << vol->cluster_size_bits, b );
if (br < 0) { if ( br < 0 )
{
ntfs_log_perror( "Error reading cluster(s)" ); ntfs_log_perror( "Error reading cluster(s)" );
return br; return br;
} }
@ -439,11 +456,13 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
{ {
s64 bw; s64 bw;
if (!vol || lcn < 0 || count < 0) { if ( !vol || lcn < 0 || count < 0 )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (vol->nr_clusters < lcn + count) { if ( vol->nr_clusters < lcn + count )
{
errno = ESPIPE; errno = ESPIPE;
ntfs_log_perror( "Trying to write outside of volume " ntfs_log_perror( "Trying to write outside of volume "
"(%lld < %lld)", ( long long )vol->nr_clusters, "(%lld < %lld)", ( long long )vol->nr_clusters,
@ -455,7 +474,8 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
count << vol->cluster_size_bits, b ); count << vol->cluster_size_bits, b );
else else
bw = count << vol->cluster_size_bits; bw = count << vol->cluster_size_bits;
if (bw < 0) { if ( bw < 0 )
{
ntfs_log_perror( "Error writing cluster(s)" ); ntfs_log_perror( "Error writing cluster(s)" );
return bw; return bw;
} }
@ -498,14 +518,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
{ {
s64 high, low; s64 high, low;
if (!dev || block_size <= 0 || (block_size - 1) & block_size) { if ( !dev || block_size <= 0 || ( block_size - 1 ) & block_size )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
#ifdef BLKGETSIZE64 #ifdef BLKGETSIZE64
{ u64 size; { u64 size;
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) { if ( dev->d_ops->ioctl( dev, BLKGETSIZE64, &size ) >= 0 )
{
ntfs_log_debug( "BLKGETSIZE64 nr bytes = %llu (0x%llx)\n", ntfs_log_debug( "BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
( unsigned long long )size, ( unsigned long long )size,
( unsigned long long )size ); ( unsigned long long )size );
@ -516,7 +538,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
#ifdef BLKGETSIZE #ifdef BLKGETSIZE
{ unsigned long size; { unsigned long size;
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) { if ( dev->d_ops->ioctl( dev, BLKGETSIZE, &size ) >= 0 )
{
ntfs_log_debug( "BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n", ntfs_log_debug( "BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
size, size ); size, size );
return ( s64 )size * 512 / block_size; return ( s64 )size * 512 / block_size;
@ -526,7 +549,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
#ifdef FDGETPRM #ifdef FDGETPRM
{ struct floppy_struct this_floppy; { struct floppy_struct this_floppy;
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) { if ( dev->d_ops->ioctl( dev, FDGETPRM, &this_floppy ) >= 0 )
{
ntfs_log_debug( "FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n", ntfs_log_debug( "FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
( unsigned long )this_floppy.size, ( unsigned long )this_floppy.size,
( unsigned long )this_floppy.size ); ( unsigned long )this_floppy.size );
@ -541,7 +565,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
low = 0LL; low = 0LL;
for ( high = 1024LL; !ntfs_device_offset_valid( dev, high ); high <<= 1 ) for ( high = 1024LL; !ntfs_device_offset_valid( dev, high ); high <<= 1 )
low = high; low = high;
while (low < high - 1LL) { while ( low < high - 1LL )
{
const s64 mid = ( low + high ) / 2; const s64 mid = ( low + high ) / 2;
if ( !ntfs_device_offset_valid( dev, mid ) ) if ( !ntfs_device_offset_valid( dev, mid ) )
@ -567,14 +592,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
*/ */
s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev ) s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev )
{ {
if (!dev) { if ( !dev )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
#ifdef HDIO_GETGEO #ifdef HDIO_GETGEO
{ struct hd_geometry geo; { struct hd_geometry geo;
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
{
ntfs_log_debug( "HDIO_GETGEO start_sect = %lu (0x%lx)\n", ntfs_log_debug( "HDIO_GETGEO start_sect = %lu (0x%lx)\n",
geo.start, geo.start ); geo.start, geo.start );
return geo.start; return geo.start;
@ -600,14 +627,16 @@ s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
*/ */
int ntfs_device_heads_get( struct ntfs_device *dev ) int ntfs_device_heads_get( struct ntfs_device *dev )
{ {
if (!dev) { if ( !dev )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
#ifdef HDIO_GETGEO #ifdef HDIO_GETGEO
{ struct hd_geometry geo; { struct hd_geometry geo;
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
{
ntfs_log_debug( "HDIO_GETGEO heads = %u (0x%x)\n", ntfs_log_debug( "HDIO_GETGEO heads = %u (0x%x)\n",
( unsigned )geo.heads, ( unsigned )geo.heads,
( unsigned )geo.heads ); ( unsigned )geo.heads );
@ -634,14 +663,16 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
*/ */
int ntfs_device_sectors_per_track_get( struct ntfs_device *dev ) int ntfs_device_sectors_per_track_get( struct ntfs_device *dev )
{ {
if (!dev) { if ( !dev )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
#ifdef HDIO_GETGEO #ifdef HDIO_GETGEO
{ struct hd_geometry geo; { struct hd_geometry geo;
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
{
ntfs_log_debug( "HDIO_GETGEO sectors_per_track = %u (0x%x)\n", ntfs_log_debug( "HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
( unsigned )geo.sectors, ( unsigned )geo.sectors,
( unsigned )geo.sectors ); ( unsigned )geo.sectors );
@ -668,7 +699,8 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
*/ */
int ntfs_device_sector_size_get( struct ntfs_device *dev ) int ntfs_device_sector_size_get( struct ntfs_device *dev )
{ {
if (!dev) { if ( !dev )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -676,7 +708,8 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
{ {
int sect_size = 0; int sect_size = 0;
if (!dev->d_ops->ioctl(dev, BLKSSZGET, &sect_size)) { if ( !dev->d_ops->ioctl( dev, BLKSSZGET, &sect_size ) )
{
ntfs_log_debug( "BLKSSZGET sector size = %d bytes\n", ntfs_log_debug( "BLKSSZGET sector size = %d bytes\n",
sect_size ); sect_size );
return sect_size; return sect_size;
@ -704,14 +737,16 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
int ntfs_device_block_size_set( struct ntfs_device *dev, int ntfs_device_block_size_set( struct ntfs_device *dev,
int block_size __attribute__( ( unused ) ) ) int block_size __attribute__( ( unused ) ) )
{ {
if (!dev) { if ( !dev )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
#ifdef BLKBSZSET #ifdef BLKBSZSET
{ {
size_t s_block_size = block_size; size_t s_block_size = block_size;
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) { if ( !dev->d_ops->ioctl( dev, BLKBSZSET, &s_block_size ) )
{
ntfs_log_debug( "Used BLKBSZSET to set block size to " ntfs_log_debug( "Used BLKBSZSET to set block size to "
"%d bytes.\n", block_size ); "%d bytes.\n", block_size );
return 0; return 0;

View File

@ -36,7 +36,8 @@
* *
* Defined bits for the state field in the ntfs_device structure. * Defined bits for the state field in the ntfs_device structure.
*/ */
typedef enum { typedef enum
{
ND_Open, /* 1: Device is open. */ ND_Open, /* 1: Device is open. */
ND_ReadOnly, /* 1: Device is read-only. */ ND_ReadOnly, /* 1: Device is read-only. */
ND_Dirty, /* 1: Device is dirty, needs sync. */ ND_Dirty, /* 1: Device is dirty, needs sync. */
@ -69,7 +70,8 @@ typedef enum {
* The ntfs device structure defining all operations needed to access the low * The ntfs device structure defining all operations needed to access the low
* level device underlying the ntfs volume. * level device underlying the ntfs volume.
*/ */
struct ntfs_device { struct ntfs_device
{
struct ntfs_device_operations *d_ops; /* Device operations. */ struct ntfs_device_operations *d_ops; /* Device operations. */
unsigned long d_state; /* State of the device. */ unsigned long d_state; /* State of the device. */
char *d_name; /* Name of device. */ char *d_name; /* Name of device. */
@ -85,7 +87,8 @@ struct stat;
* The ntfs device operations defining all operations that can be performed on * The ntfs device operations defining all operations that can be performed on
* the low level device described by an ntfs device structure. * the low level device described by an ntfs device structure.
*/ */
struct ntfs_device_operations { struct ntfs_device_operations
{
int ( *open )( struct ntfs_device *dev, int flags ); int ( *open )( struct ntfs_device *dev, int flags );
int ( *close )( struct ntfs_device *dev ); int ( *close )( struct ntfs_device *dev );
s64 ( *seek )( struct ntfs_device *dev, s64 offset, int whence ); s64 ( *seek )( struct ntfs_device *dev, s64 offset, int whence );

View File

@ -45,7 +45,8 @@
/** /**
* struct hd_geometry - * struct hd_geometry -
*/ */
struct hd_geometry { struct hd_geometry
{
unsigned char heads; unsigned char heads;
unsigned char sectors; unsigned char sectors;
unsigned short cylinders; unsigned short cylinders;

File diff suppressed because it is too large Load Diff

View File

@ -60,7 +60,8 @@
#ifdef HAVE_SETXATTR /* extended attributes interface required */ #ifdef HAVE_SETXATTR /* extended attributes interface required */
static ntfschar logged_utility_stream_name[] = { static ntfschar logged_utility_stream_name[] =
{
const_cpu_to_le16( '$' ), const_cpu_to_le16( '$' ),
const_cpu_to_le16( 'E' ), const_cpu_to_le16( 'E' ),
const_cpu_to_le16( 'F' ), const_cpu_to_le16( 'F' ),
@ -78,32 +79,43 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
EFS_ATTR_HEADER *efs_info; EFS_ATTR_HEADER *efs_info;
s64 attr_size = 0; s64 attr_size = 0;
if (ni) { if ( ni )
if (ni->flags & FILE_ATTR_ENCRYPTED) { {
if ( ni->flags & FILE_ATTR_ENCRYPTED )
{
efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni, efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni,
AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0, AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0,
&attr_size ); &attr_size );
if ( efs_info if ( efs_info
&& (le32_to_cpu(efs_info->length) == attr_size)) { && ( le32_to_cpu( efs_info->length ) == attr_size ) )
if (attr_size <= (s64)size) { {
if ( attr_size <= ( s64 )size )
{
if ( value ) if ( value )
memcpy( value, efs_info, attr_size ); memcpy( value, efs_info, attr_size );
else { else
{
errno = EFAULT; errno = EFAULT;
attr_size = 0; attr_size = 0;
} }
} else }
if (size) { else if ( size )
{
errno = ERANGE; errno = ERANGE;
attr_size = 0; attr_size = 0;
} }
free ( efs_info ); free ( efs_info );
} else { }
if (efs_info) { else
{
if ( efs_info )
{
free( efs_info ); free( efs_info );
ntfs_log_error( "Bad efs_info for inode %lld\n", ntfs_log_error( "Bad efs_info for inode %lld\n",
( long long )ni->mft_no ); ( long long )ni->mft_no );
} else { }
else
{
ntfs_log_error( "Could not get efsinfo" ntfs_log_error( "Could not get efsinfo"
" for inode %lld\n", " for inode %lld\n",
( long long )ni->mft_no ); ( long long )ni->mft_no );
@ -111,7 +123,9 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
errno = EIO; errno = EIO;
attr_size = 0; attr_size = 0;
} }
} else { }
else
{
errno = ENODATA; errno = ENODATA;
ntfs_log_trace( "Inode %lld is not encrypted\n", ntfs_log_trace( "Inode %lld is not encrypted\n",
( long long )ni->mft_no ); ( long long )ni->mft_no );
@ -145,45 +159,57 @@ static int fixup_loop(ntfs_inode *ni)
int res = 0; int res = 0;
maxcnt = 0; maxcnt = 0;
do { do
{
restart = FALSE; restart = FALSE;
ctx = ntfs_attr_get_search_ctx( ni, NULL ); ctx = ntfs_attr_get_search_ctx( ni, NULL );
if (!ctx) { if ( !ctx )
{
ntfs_log_error( "Failed to get ctx for efs\n" ); ntfs_log_error( "Failed to get ctx for efs\n" );
res = -1; res = -1;
} }
cnt = 0; cnt = 0;
while ( !restart && !res while ( !restart && !res
&& !ntfs_attr_lookup( AT_DATA, NULL, 0, && !ntfs_attr_lookup( AT_DATA, NULL, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) { CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
cnt++; cnt++;
a = ctx->attr; a = ctx->attr;
na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA, na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA,
( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ), ( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ),
a->name_length ); a->name_length );
if (!na) { if ( !na )
{
ntfs_log_error( "can't open DATA Attribute\n" ); ntfs_log_error( "can't open DATA Attribute\n" );
res = -1; res = -1;
} }
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) { if ( na && !( ctx->attr->flags & ATTR_IS_ENCRYPTED ) )
{
if ( !NAttrNonResident( na ) if ( !NAttrNonResident( na )
&& ntfs_attr_make_non_resident(na, ctx)) { && ntfs_attr_make_non_resident( na, ctx ) )
{
/* /*
* ntfs_attr_make_non_resident fails if there * ntfs_attr_make_non_resident fails if there
* is not enough space in the MFT record. * is not enough space in the MFT record.
* When this happens, force making non-resident * When this happens, force making non-resident
* so that some other attribute is expelled. * so that some other attribute is expelled.
*/ */
if (ntfs_attr_force_non_resident(na)) { if ( ntfs_attr_force_non_resident( na ) )
{
res = -1; res = -1;
} else { }
else
{
/* make sure there is some progress */ /* make sure there is some progress */
if (cnt <= maxcnt) { if ( cnt <= maxcnt )
{
errno = EIO; errno = EIO;
ntfs_log_error( "Multiple failure" ntfs_log_error( "Multiple failure"
" making non resident\n" ); " making non resident\n" );
res = -1; res = -1;
} else { }
else
{
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
ctx = ( ntfs_attr_search_ctx* )NULL; ctx = ( ntfs_attr_search_ctx* )NULL;
restart = TRUE; restart = TRUE;
@ -192,7 +218,8 @@ static int fixup_loop(ntfs_inode *ni)
} }
} }
if ( !restart && !res if ( !restart && !res
&& ntfs_efs_fixup_attribute(ctx, na)) { && ntfs_efs_fixup_attribute( ctx, na ) )
{
ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" ); ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" );
res = -1; res = -1;
} }
@ -201,7 +228,8 @@ static int fixup_loop(ntfs_inode *ni)
ntfs_attr_close( na ); ntfs_attr_close( na );
} }
first = FALSE; first = FALSE;
} while (restart && !res); }
while ( restart && !res );
if ( ctx ) if ( ctx )
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
return ( res ); return ( res );
@ -223,13 +251,18 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
const EFS_ATTR_HEADER *info_header; const EFS_ATTR_HEADER *info_header;
res = 0; res = 0;
if (ni && value && size) { if ( ni && value && size )
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) { {
if (ni->flags & FILE_ATTR_ENCRYPTED) { if ( ni->flags & ( FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED ) )
{
if ( ni->flags & FILE_ATTR_ENCRYPTED )
{
ntfs_log_trace( "Inode %lld already encrypted\n", ntfs_log_trace( "Inode %lld already encrypted\n",
( long long )ni->mft_no ); ( long long )ni->mft_no );
errno = EEXIST; errno = EEXIST;
} else { }
else
{
/* /*
* Possible problem : if encrypted file was * Possible problem : if encrypted file was
* restored in a compressed directory, it was * restored in a compressed directory, it was
@ -244,13 +277,16 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
} }
info_header = ( const EFS_ATTR_HEADER* )value; info_header = ( const EFS_ATTR_HEADER* )value;
/* make sure we get a likely efsinfo */ /* make sure we get a likely efsinfo */
if (le32_to_cpu(info_header->length) != size) { if ( le32_to_cpu( info_header->length ) != size )
{
errno = EINVAL; errno = EINVAL;
return ( -1 ); return ( -1 );
} }
if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM, if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM,
(ntfschar*)NULL,0)) { ( ntfschar* )NULL, 0 ) )
if (!(flags & XATTR_REPLACE)) { {
if ( !( flags & XATTR_REPLACE ) )
{
/* /*
* no logged_utility_stream attribute : add one, * no logged_utility_stream attribute : add one,
* apparently, this does not feed the new value in * apparently, this does not feed the new value in
@ -258,28 +294,36 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM, res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM,
logged_utility_stream_name, 4, logged_utility_stream_name, 4,
( u8* )NULL, ( s64 )size ); ( u8* )NULL, ( s64 )size );
} else { }
else
{
errno = ENODATA; errno = ENODATA;
res = -1; res = -1;
} }
} else { }
else
{
errno = EEXIST; errno = EEXIST;
res = -1; res = -1;
} }
if (!res) { if ( !res )
{
/* /*
* open and update the existing efs data * open and update the existing efs data
*/ */
na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM, na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM,
logged_utility_stream_name, 4 ); logged_utility_stream_name, 4 );
if (na) { if ( na )
{
/* resize attribute */ /* resize attribute */
res = ntfs_attr_truncate( na, ( s64 )size ); res = ntfs_attr_truncate( na, ( s64 )size );
/* overwrite value if any */ /* overwrite value if any */
if (!res && value) { if ( !res && value )
{
written = ( int )ntfs_attr_pwrite( na, written = ( int )ntfs_attr_pwrite( na,
( s64 )0, ( s64 )size, value ); ( s64 )0, ( s64 )size, value );
if (written != (s64)size) { if ( written != ( s64 )size )
{
ntfs_log_error( "Failed to " ntfs_log_error( "Failed to "
"update efs data\n" ); "update efs data\n" );
errno = EIO; errno = EIO;
@ -287,12 +331,15 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
} }
} }
ntfs_attr_close( na ); ntfs_attr_close( na );
} else }
else
res = -1; res = -1;
} }
if (!res) { if ( !res )
{
/* Don't handle AT_DATA Attribute(s) if inode is a directory */ /* Don't handle AT_DATA Attribute(s) if inode is a directory */
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { if ( !( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
{
/* iterate over AT_DATA attributes */ /* iterate over AT_DATA attributes */
/* set encrypted flag, truncate attribute to match padding bytes */ /* set encrypted flag, truncate attribute to match padding bytes */
@ -303,7 +350,9 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
NInoSetDirty( ni ); NInoSetDirty( ni );
NInoFileNameSetDirty( ni ); NInoFileNameSetDirty( ni );
} }
} else { }
else
{
errno = EINVAL; errno = EINVAL;
res = -1; res = -1;
} }
@ -330,24 +379,31 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
ntfs_inode *ni; ntfs_inode *ni;
BOOL close_ctx = FALSE; BOOL close_ctx = FALSE;
if (!na) { if ( !na )
{
ntfs_log_error( "no na specified for efs_fixup_attribute\n" ); ntfs_log_error( "no na specified for efs_fixup_attribute\n" );
goto err_out; goto err_out;
} }
if (!ctx) { if ( !ctx )
{
ctx = ntfs_attr_get_search_ctx( na->ni, NULL ); ctx = ntfs_attr_get_search_ctx( na->ni, NULL );
if (!ctx) { if ( !ctx )
{
ntfs_log_error( "Failed to get ctx for efs\n" ); ntfs_log_error( "Failed to get ctx for efs\n" );
goto err_out; goto err_out;
} }
close_ctx = TRUE; close_ctx = TRUE;
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len, if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
CASE_SENSITIVE, 0, NULL, 0, ctx)) { CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" ); ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
goto err_out; goto err_out;
} }
} else { }
if (!NAttrNonResident(na)) { else
{
if ( !NAttrNonResident( na ) )
{
ntfs_log_error( "Cannot make non resident" ntfs_log_error( "Cannot make non resident"
" when a context has been allocated\n" ); " when a context has been allocated\n" );
goto err_out; goto err_out;
@ -356,19 +412,23 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
/* no extra bytes are added to void attributes */ /* no extra bytes are added to void attributes */
oldsize = na->data_size; oldsize = na->data_size;
if (oldsize) { if ( oldsize )
{
/* make sure size is valid for a raw encrypted stream */ /* make sure size is valid for a raw encrypted stream */
if ((oldsize & 511) != 2) { if ( ( oldsize & 511 ) != 2 )
{
ntfs_log_error( "Bad raw encrypted stream\n" ); ntfs_log_error( "Bad raw encrypted stream\n" );
goto err_out; goto err_out;
} }
/* read padding length from last two bytes of attribute */ /* read padding length from last two bytes of attribute */
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) { if ( ntfs_attr_pread( na, oldsize - 2, 2, &appended_bytes ) != 2 )
{
ntfs_log_error( "Error reading padding length\n" ); ntfs_log_error( "Error reading padding length\n" );
goto err_out; goto err_out;
} }
padding_length = le16_to_cpu( appended_bytes ); padding_length = le16_to_cpu( appended_bytes );
if (padding_length > 511 || padding_length > na->data_size-2) { if ( padding_length > 511 || padding_length > na->data_size - 2 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_error( "invalid padding length %d for data_size %lld\n", ntfs_log_error( "invalid padding length %d for data_size %lld\n",
padding_length, ( long long )oldsize ); padding_length, ( long long )oldsize );
@ -380,11 +440,13 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
* for the last two bytes, but do not truncate to new size * for the last two bytes, but do not truncate to new size
* to avoid losing useful data * to avoid losing useful data
*/ */
if (ntfs_attr_truncate(na, oldsize - 2)) { if ( ntfs_attr_truncate( na, oldsize - 2 ) )
{
ntfs_log_error( "Error truncating attribute\n" ); ntfs_log_error( "Error truncating attribute\n" );
goto err_out; goto err_out;
} }
} else }
else
newsize = 0; newsize = 0;
/* /*
@ -394,12 +456,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
* resident. * resident.
*/ */
if ( !NAttrNonResident( na ) if ( !NAttrNonResident( na )
&& ntfs_attr_make_non_resident(na, ctx)) { && ntfs_attr_make_non_resident( na, ctx ) )
{
if ( !close_ctx if ( !close_ctx
|| ntfs_attr_force_non_resident(na)) { || ntfs_attr_force_non_resident( na ) )
{
ntfs_log_error( "Error making DATA attribute non-resident\n" ); ntfs_log_error( "Error making DATA attribute non-resident\n" );
goto err_out; goto err_out;
} else { }
else
{
/* /*
* must reinitialize context after forcing * must reinitialize context after forcing
* non-resident. We need a context for updating * non-resident. We need a context for updating
@ -408,14 +474,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
*/ */
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len, if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
CASE_SENSITIVE, 0, NULL, 0, ctx)) { CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" ); ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
goto err_out; goto err_out;
} }
} }
} }
ni = na->ni; ni = na->ni;
if (!na->name_len) { if ( !na->name_len )
{
ni->data_size = newsize; ni->data_size = newsize;
ni->allocated_size = na->allocated_size; ni->allocated_size = na->allocated_size;
} }

View File

@ -80,32 +80,37 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
// Get the device interface // Get the device interface
const DISC_INTERFACE* interface = fd->interface; const DISC_INTERFACE* interface = fd->interface;
if (!interface) { if ( !interface )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
// Start the device interface and ensure that it is inserted // Start the device interface and ensure that it is inserted
if (!interface->startup()) { if ( !interface->startup() )
{
ntfs_log_perror( "device failed to start\n" ); ntfs_log_perror( "device failed to start\n" );
errno = EIO; errno = EIO;
return -1; return -1;
} }
if (!interface->isInserted()) { if ( !interface->isInserted() )
{
ntfs_log_perror( "device media is not inserted\n" ); ntfs_log_perror( "device media is not inserted\n" );
errno = EIO; errno = EIO;
return -1; return -1;
} }
// Check that the device isn't already open (used by another volume?) // Check that the device isn't already open (used by another volume?)
if (NDevOpen(dev)) { if ( NDevOpen( dev ) )
{
ntfs_log_perror( "device is busy (already open)\n" ); ntfs_log_perror( "device is busy (already open)\n" );
errno = EBUSY; errno = EBUSY;
return -1; return -1;
@ -113,12 +118,16 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
// Check that there is a valid NTFS boot sector at the start of the device // Check that there is a valid NTFS boot sector at the start of the device
NTFS_BOOT_SECTOR boot; NTFS_BOOT_SECTOR boot;
if (interface->readSectors(fd->startSector, 1, &boot)) { if ( interface->readSectors( fd->startSector, 1, &boot ) )
if (!ntfs_boot_sector_is_ntfs(&boot)) { {
if ( !ntfs_boot_sector_is_ntfs( &boot ) )
{
errno = EINVALPART; errno = EINVALPART;
return -1; return -1;
} }
} else { }
else
{
ntfs_log_perror( "read failure @ sector %d\n", fd->startSector ); ntfs_log_perror( "read failure @ sector %d\n", fd->startSector );
errno = EIO; errno = EIO;
return -1; return -1;
@ -133,7 +142,8 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
fd->ino = le64_to_cpu( boot.volume_serial_number ); fd->ino = le64_to_cpu( boot.volume_serial_number );
// Mark the device as read-only (if required) // Mark the device as read-only (if required)
if (flags & O_RDONLY) { if ( flags & O_RDONLY )
{
NDevSetReadOnly( dev ); NDevSetReadOnly( dev );
} }
@ -156,13 +166,15 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
// Check that the device is actually open // Check that the device is actually open
if (!NDevOpen(dev)) { if ( !NDevOpen( dev ) )
{
ntfs_log_perror( "device is not open\n" ); ntfs_log_perror( "device is not open\n" );
errno = EIO; errno = EIO;
return -1; return -1;
@ -173,7 +185,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
NDevClearBlock( dev ); NDevClearBlock( dev );
// Flush the device (if dirty and not read-only) // Flush the device (if dirty and not read-only)
if (NDevDirty(dev) && !NDevReadOnly(dev)) { if ( NDevDirty( dev ) && !NDevReadOnly( dev ) )
{
ntfs_log_debug( "device is dirty, will now sync\n" ); ntfs_log_debug( "device is dirty, will now sync\n" );
// ...? // ...?
@ -184,7 +197,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
} }
// Flush and destroy the cache (if required) // Flush and destroy the cache (if required)
if (fd->cache) { if ( fd->cache )
{
_NTFS_cache_flush( fd->cache ); _NTFS_cache_flush( fd->cache );
_NTFS_cache_destructor( fd->cache ); _NTFS_cache_destructor( fd->cache );
} }
@ -211,13 +225,15 @@ static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int wh
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
// Set the current position on the device (in bytes) // Set the current position on the device (in bytes)
switch(whence) { switch ( whence )
{
case SEEK_SET: fd->pos = MIN( MAX( offset, 0 ), fd->len ); break; case SEEK_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_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; case SEEK_END: fd->pos = MIN( MAX( fd->len + offset, 0 ), fd->len ); break;
@ -267,14 +283,16 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
// Get the device interface // Get the device interface
const DISC_INTERFACE* interface = fd->interface; const DISC_INTERFACE* interface = fd->interface;
if (!interface) { if ( !interface )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
@ -294,20 +312,24 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
u8 *buffer = NULL; u8 *buffer = NULL;
// Determine the range of sectors required for this read // Determine the range of sectors required for this read
if (offset > 0) { if ( offset > 0 )
{
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize ); sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
} }
if (buffer_offset+count > fd->sectorSize) { if ( buffer_offset + count > fd->sectorSize )
{
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize ); sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
} }
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer // If this read happens to be on the sector boundaries then do the read straight into the destination buffer
if((buffer_offset == 0) && (count % fd->sectorSize == 0)) { if ( ( buffer_offset == 0 ) && ( count % fd->sectorSize == 0 ) )
{
// Read from the device // Read from the device
ntfs_log_trace( "direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count ); ntfs_log_trace( "direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) { if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buf ) )
{
ntfs_log_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count ); ntfs_log_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
errno = EIO; errno = EIO;
return -1; return -1;
@ -320,7 +342,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
// Allocate a buffer to hold the read data // Allocate a buffer to hold the read data
buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize ); buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize );
if (!buffer) { if ( !buffer )
{
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
@ -328,7 +351,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
// Read from the device // Read from the device
ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count ); ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
ntfs_log_trace( "count: %d sec_count:%d fd->sectorSize: %d )\n", ( u32 )count, ( u32 )sec_count, ( u32 )fd->sectorSize ); ntfs_log_trace( "count: %d sec_count:%d fd->sectorSize: %d )\n", ( u32 )count, ( u32 )sec_count, ( u32 )fd->sectorSize );
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) { if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buffer ) )
{
ntfs_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count ); ntfs_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
ntfs_free( buffer ); ntfs_free( buffer );
errno = EIO; errno = EIO;
@ -353,25 +377,29 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
// Get the device interface // Get the device interface
const DISC_INTERFACE* interface = fd->interface; const DISC_INTERFACE* interface = fd->interface;
if (!interface) { if ( !interface )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
// Check that the device can be written to // Check that the device can be written to
if (NDevReadOnly(dev)) { if ( NDevReadOnly( dev ) )
{
errno = EROFS; errno = EROFS;
return -1; return -1;
} }
if(count < 0 || offset < 0) { if ( count < 0 || offset < 0 )
{
errno = EROFS; errno = EROFS;
return -1; return -1;
} }
@ -385,10 +413,12 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
u8 *buffer = NULL; u8 *buffer = NULL;
// Determine the range of sectors required for this write // Determine the range of sectors required for this write
if (offset > 0) { if ( offset > 0 )
{
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize ); sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
} }
if ((buffer_offset+count) > fd->sectorSize) { if ( ( buffer_offset + count ) > fd->sectorSize )
{
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize ); sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
} }
@ -397,7 +427,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
{ {
// Write to the device // Write to the device
ntfs_log_trace( "direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count ); ntfs_log_trace( "direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) { if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buf ) )
{
ntfs_log_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count ); ntfs_log_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
errno = EIO; errno = EIO;
return -1; return -1;
@ -408,7 +439,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
{ {
// Allocate a buffer to hold the write data // Allocate a buffer to hold the write data
buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize ); buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize );
if (!buffer) { if ( !buffer )
{
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
@ -417,7 +449,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 // we just read in the buffer edges where the data overlaps with the rest of the disc
if ( buffer_offset != 0 ) if ( buffer_offset != 0 )
{ {
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) { if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, 1, buffer ) )
{
ntfs_log_perror( "read failure @ sector %d\n", sec_start ); ntfs_log_perror( "read failure @ sector %d\n", sec_start );
ntfs_free( buffer ); ntfs_free( buffer );
errno = EIO; errno = EIO;
@ -426,7 +459,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
} }
if ( ( buffer_offset + count ) % fd->sectorSize != 0 ) if ( ( buffer_offset + count ) % fd->sectorSize != 0 )
{ {
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) { if ( !ntfs_device_gekko_io_readsectors( dev, sec_start + sec_count - 1, 1, buffer + ( ( sec_count - 1 ) * fd->sectorSize ) ) )
{
ntfs_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 ); ntfs_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 );
ntfs_free( buffer ); ntfs_free( buffer );
errno = EIO; errno = EIO;
@ -439,7 +473,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
// Write to the device // Write to the device
ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count ); ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) { if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buffer ) )
{
ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start ); ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start );
ntfs_free( buffer ); ntfs_free( buffer );
errno = EIO; errno = EIO;
@ -460,7 +495,8 @@ static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sect
{ {
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return false; return false;
} }
@ -477,7 +513,8 @@ static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sec
{ {
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return false; return false;
} }
@ -500,7 +537,8 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
ntfs_log_trace( "dev %p\n", dev ); ntfs_log_trace( "dev %p\n", dev );
// Check that the device can be written to // Check that the device can be written to
if (NDevReadOnly(dev)) { if ( NDevReadOnly( dev ) )
{
errno = EROFS; errno = EROFS;
return -1; return -1;
} }
@ -509,8 +547,10 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
NDevClearDirty( dev ); NDevClearDirty( dev );
// Flush any sectors in the disc cache (if required) // Flush any sectors in the disc cache (if required)
if (fd->cache) { if ( fd->cache )
if (!_NTFS_cache_flush(fd->cache)) { {
if ( !_NTFS_cache_flush( fd->cache ) )
{
errno = EIO; errno = EIO;
return -1; return -1;
} }
@ -528,7 +568,8 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
@ -565,17 +606,20 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
// Get the device driver descriptor // Get the device driver descriptor
gekko_fd *fd = DEV_FD( dev ); gekko_fd *fd = DEV_FD( dev );
if (!fd) { if ( !fd )
{
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
// Figure out which i/o control was requested // Figure out which i/o control was requested
switch (request) { switch ( request )
{
// Get block device size (sectors) // Get block device size (sectors)
#if defined(BLKGETSIZE) #if defined(BLKGETSIZE)
case BLKGETSIZE: { case BLKGETSIZE:
{
*( u32* )argp = fd->sectorCount; *( u32* )argp = fd->sectorCount;
return 0; return 0;
} }
@ -583,7 +627,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
// Get block device size (bytes) // Get block device size (bytes)
#if defined(BLKGETSIZE64) #if defined(BLKGETSIZE64)
case BLKGETSIZE64: { case BLKGETSIZE64:
{
*( u64* )argp = ( fd->sectorCount * fd->sectorSize ); *( u64* )argp = ( fd->sectorCount * fd->sectorSize );
return 0; return 0;
} }
@ -591,7 +636,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
// Get hard drive geometry // Get hard drive geometry
#if defined(HDIO_GETGEO) #if defined(HDIO_GETGEO)
case HDIO_GETGEO: { case HDIO_GETGEO:
{
struct hd_geometry *geo = ( struct hd_geometry* )argp; struct hd_geometry *geo = ( struct hd_geometry* )argp;
geo->sectors = 0; geo->sectors = 0;
geo->heads = 0; geo->heads = 0;
@ -603,7 +649,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
// Get block device sector size (bytes) // Get block device sector size (bytes)
#if defined(BLKSSZGET) #if defined(BLKSSZGET)
case BLKSSZGET: { case BLKSSZGET:
{
*( int* )argp = fd->sectorSize; *( int* )argp = fd->sectorSize;
return 0; return 0;
} }
@ -611,7 +658,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
// Set block device block size (bytes) // Set block device block size (bytes)
#if defined(BLKBSZSET) #if defined(BLKBSZSET)
case BLKBSZSET: { case BLKBSZSET:
{
int sectorSize = *( int* )argp; int sectorSize = *( int* )argp;
fd->sectorSize = sectorSize; fd->sectorSize = sectorSize;
return 0; return 0;
@ -619,7 +667,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
#endif #endif
// Unimplemented ioctrl // Unimplemented ioctrl
default: { default:
{
ntfs_log_perror( "Unimplemented ioctrl %i\n", request ); ntfs_log_perror( "Unimplemented ioctrl %i\n", request );
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
return -1; return -1;
@ -633,7 +682,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
/** /**
* Device operations for working with gekko style devices and files. * Device operations for working with gekko style devices and files.
*/ */
struct ntfs_device_operations ntfs_device_gekko_io_ops = { struct ntfs_device_operations ntfs_device_gekko_io_ops =
{
.open = ntfs_device_gekko_io_open, .open = ntfs_device_gekko_io_open,
.close = ntfs_device_gekko_io_close, .close = ntfs_device_gekko_io_close,
.seek = ntfs_device_gekko_io_seek, .seek = ntfs_device_gekko_io_seek,

View File

@ -33,7 +33,8 @@
/** /**
* gekko_fd - Gekko device driver descriptor * gekko_fd - Gekko device driver descriptor
*/ */
typedef struct _gekko_fd { typedef struct _gekko_fd
{
const DISC_INTERFACE* interface; /* Device disc interface */ const DISC_INTERFACE* interface; /* Device disc interface */
sec_t startSector; /* LBA of partition start */ sec_t startSector; /* LBA of partition start */
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */ sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */

View File

@ -88,7 +88,8 @@ static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib)
ret = ntfs_attr_mst_pwrite( icx->ia_na, ntfs_ib_vcn_to_pos( icx, vcn ), ret = ntfs_attr_mst_pwrite( icx->ia_na, ntfs_ib_vcn_to_pos( icx, vcn ),
1, icx->block_size, ib ); 1, icx->block_size, ib );
if (ret != 1) { if ( ret != 1 )
{
ntfs_log_perror( "Failed to write index block %lld, inode %llu", ntfs_log_perror( "Failed to write index block %lld, inode %llu",
( long long )vcn, ( unsigned long long )icx->ni->mft_no ); ( long long )vcn, ( unsigned long long )icx->ni->mft_no );
return STATUS_ERROR; return STATUS_ERROR;
@ -123,7 +124,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
if (!ni) { if ( !ni )
{
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
@ -131,7 +133,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
ni = ni->base_ni; ni = ni->base_ni;
icx = ntfs_calloc( sizeof( ntfs_index_context ) ); icx = ntfs_calloc( sizeof( ntfs_index_context ) );
if ( icx ) if ( icx )
*icx = (ntfs_index_context) { *icx = ( ntfs_index_context )
{
.ni = ni, .ni = ni,
.name = name, .name = name,
.name_len = name_len, .name_len = name_len,
@ -149,8 +152,10 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
if ( icx->actx ) if ( icx->actx )
ntfs_attr_put_search_ctx( icx->actx ); ntfs_attr_put_search_ctx( icx->actx );
if (!icx->is_in_root) { if ( !icx->is_in_root )
if (icx->ib_dirty) { {
if ( icx->ib_dirty )
{
/* FIXME: Error handling!!! */ /* FIXME: Error handling!!! */
ntfs_ib_write( icx, icx->ib ); ntfs_ib_write( icx, icx->ib );
} }
@ -184,7 +189,8 @@ void ntfs_index_ctx_reinit(ntfs_index_context *icx)
ntfs_index_ctx_free( icx ); ntfs_index_ctx_free( icx );
*icx = (ntfs_index_context) { *icx = ( ntfs_index_context )
{
.ni = icx->ni, .ni = icx->ni,
.name = icx->name, .name = icx->name,
.name_len = icx->name_len, .name_len = icx->name_len,
@ -261,7 +267,8 @@ static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie)
tmp = ntfs_ie_get_first( ih ); tmp = ntfs_ie_get_first( ih );
while (tmp != ie) { while ( tmp != ie )
{
ie_prev = tmp; ie_prev = tmp;
tmp = ntfs_ie_get_next( tmp ); tmp = ntfs_ie_get_next( tmp );
} }
@ -293,7 +300,8 @@ void ntfs_ih_filename_dump(INDEX_HEADER *ih)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
ie = ntfs_ie_get_first( ih ); ie = ntfs_ie_get_first( ih );
while (!ntfs_ie_end(ie)) { while ( !ntfs_ie_end( ie ) )
{
ntfs_ie_filename_dump( ie ); ntfs_ie_filename_dump( ie );
ie = ntfs_ie_get_next( ie ); ie = ntfs_ie_get_next( ie );
} }
@ -380,7 +388,8 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
size -= sizeof( VCN ); size -= sizeof( VCN );
dup = ntfs_malloc( size ); dup = ntfs_malloc( size );
if (dup) { if ( dup )
{
memcpy( dup, ie, size ); memcpy( dup, ie, size );
dup->ie_flags &= ~INDEX_ENTRY_NODE; dup->ie_flags &= ~INDEX_ENTRY_NODE;
dup->length = cpu_to_le16( size ); dup->length = cpu_to_le16( size );
@ -394,7 +403,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
if (!ntfs_is_indx_record(ib->magic)) { if ( !ntfs_is_indx_record( ib->magic ) )
{
ntfs_log_error( "Corrupt index block signature: vcn %lld inode " ntfs_log_error( "Corrupt index block signature: vcn %lld inode "
"%llu\n", ( long long )vcn, "%llu\n", ( long long )vcn,
@ -402,7 +412,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
return -1; return -1;
} }
if (sle64_to_cpu(ib->index_block_vcn) != vcn) { if ( sle64_to_cpu( ib->index_block_vcn ) != vcn )
{
ntfs_log_error( "Corrupt index block: VCN (%lld) is different " ntfs_log_error( "Corrupt index block: VCN (%lld) is different "
"from expected VCN (%lld) in inode %llu\n", "from expected VCN (%lld) in inode %llu\n",
@ -412,7 +423,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
return -1; return -1;
} }
if (ib_size != icx->block_size) { if ( ib_size != icx->block_size )
{
ntfs_log_error( "Corrupt index block : VCN (%lld) of inode %llu " ntfs_log_error( "Corrupt index block : VCN (%lld) of inode %llu "
"has a size (%u) differing from the index " "has a size (%u) differing from the index "
@ -437,13 +449,15 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
return NULL; return NULL;
if ( ntfs_attr_lookup( AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, if ( ntfs_attr_lookup( AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE,
0, NULL, 0, *ctx)) { 0, NULL, 0, *ctx ) )
{
ntfs_log_perror( "Failed to lookup $INDEX_ROOT" ); ntfs_log_perror( "Failed to lookup $INDEX_ROOT" );
goto err_out; goto err_out;
} }
a = ( *ctx )->attr; a = ( *ctx )->attr;
if (a->non_resident) { if ( a->non_resident )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "Non-resident $INDEX_ROOT detected" ); ntfs_log_perror( "Non-resident $INDEX_ROOT detected" );
goto err_out; goto err_out;
@ -451,7 +465,8 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
ir = ( INDEX_ROOT * )( ( char * )a + le16_to_cpu( a->value_offset ) ); ir = ( INDEX_ROOT * )( ( char * )a + le16_to_cpu( a->value_offset ) );
err_out: err_out:
if (!ir) { if ( !ir )
{
ntfs_attr_put_search_ctx( *ctx ); ntfs_attr_put_search_ctx( *ctx );
*ctx = NULL; *ctx = NULL;
} }
@ -497,10 +512,12 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
* Loop until we exceed valid memory (corruption case) or until we * Loop until we exceed valid memory (corruption case) or until we
* reach the last entry. * reach the last entry.
*/ */
for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) { for ( ie = ntfs_ie_get_first( ih ); ; ie = ntfs_ie_get_next( ie ) )
{
/* Bounds checks. */ /* Bounds checks. */
if ( ( u8 * )ie + sizeof( INDEX_ENTRY_HEADER ) > index_end || if ( ( u8 * )ie + sizeof( INDEX_ENTRY_HEADER ) > index_end ||
(u8 *)ie + le16_to_cpu(ie->length) > index_end) { ( u8 * )ie + le16_to_cpu( ie->length ) > index_end )
{
errno = ERANGE; errno = ERANGE;
ntfs_log_error( "Index entry out of bounds in inode " ntfs_log_error( "Index entry out of bounds in inode "
"%llu.\n", "%llu.\n",
@ -517,14 +534,16 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
* Not a perfect match, need to do full blown collation so we * Not a perfect match, need to do full blown collation so we
* know which way in the B+tree we have to go. * know which way in the B+tree we have to go.
*/ */
if (!icx->collate) { if ( !icx->collate )
{
ntfs_log_error( "Collation function not defined\n" ); ntfs_log_error( "Collation function not defined\n" );
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
return STATUS_ERROR; return STATUS_ERROR;
} }
rc = icx->collate( icx->ni->vol, key, key_len, rc = icx->collate( icx->ni->vol, key, key_len,
&ie->key, le16_to_cpu( ie->key_length ) ); &ie->key, le16_to_cpu( ie->key_length ) );
if (rc == NTFS_COLLATION_ERROR) { if ( rc == NTFS_COLLATION_ERROR )
{
ntfs_log_error( "Collation error. Perhaps a filename " ntfs_log_error( "Collation error. Perhaps a filename "
"contains invalid characters?\n" ); "contains invalid characters?\n" );
errno = ERANGE; errno = ERANGE;
@ -538,7 +557,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
if ( rc == -1 ) if ( rc == -1 )
break; break;
if (!rc) { if ( !rc )
{
*ie_out = ie; *ie_out = ie;
errno = 0; errno = 0;
icx->parent_pos[icx->pindex] = item; icx->parent_pos[icx->pindex] = item;
@ -552,7 +572,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
* presence of a child node and if not present return with errno ENOENT, * presence of a child node and if not present return with errno ENOENT,
* otherwise we will keep searching in another index block. * otherwise we will keep searching in another index block.
*/ */
if (!(ie->ie_flags & INDEX_ENTRY_NODE)) { if ( !( ie->ie_flags & INDEX_ENTRY_NODE ) )
{
ntfs_log_debug( "Index entry wasn't found.\n" ); ntfs_log_debug( "Index entry wasn't found.\n" );
*ie_out = ie; *ie_out = ie;
errno = ENOENT; errno = ENOENT;
@ -561,7 +582,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
/* Get the starting vcn of the index_block holding the child node. */ /* Get the starting vcn of the index_block holding the child node. */
*vcn = ntfs_ie_get_vcn( ie ); *vcn = ntfs_ie_get_vcn( ie );
if (*vcn < 0) { if ( *vcn < 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "Negative vcn in inode %llu", ntfs_log_perror( "Negative vcn in inode %llu",
( unsigned long long )icx->ni->mft_no ); ( unsigned long long )icx->ni->mft_no );
@ -579,7 +601,8 @@ static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni)
ntfs_attr *na; ntfs_attr *na;
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len ); na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len );
if (!na) { if ( !na )
{
ntfs_log_perror( "Failed to open index allocation of inode " ntfs_log_perror( "Failed to open index allocation of inode "
"%llu", ( unsigned long long )ni->mft_no ); "%llu", ( unsigned long long )ni->mft_no );
return NULL; return NULL;
@ -597,7 +620,8 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
pos = ntfs_ib_vcn_to_pos( icx, vcn ); pos = ntfs_ib_vcn_to_pos( icx, vcn );
ret = ntfs_attr_mst_pread( icx->ia_na, pos, 1, icx->block_size, ( u8 * )dst ); ret = ntfs_attr_mst_pread( icx->ia_na, pos, 1, icx->block_size, ( u8 * )dst );
if (ret != 1) { if ( ret != 1 )
{
if ( ret == -1 ) if ( ret == -1 )
ntfs_log_perror( "Failed to read index block" ); ntfs_log_perror( "Failed to read index block" );
else else
@ -615,7 +639,8 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
static int ntfs_icx_parent_inc( ntfs_index_context *icx ) static int ntfs_icx_parent_inc( ntfs_index_context *icx )
{ {
icx->pindex++; icx->pindex++;
if (icx->pindex >= MAX_PARENT_VCN) { if ( icx->pindex >= MAX_PARENT_VCN )
{
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
ntfs_log_perror( "Index is over %d level deep", MAX_PARENT_VCN ); ntfs_log_perror( "Index is over %d level deep", MAX_PARENT_VCN );
return STATUS_ERROR; return STATUS_ERROR;
@ -626,7 +651,8 @@ static int ntfs_icx_parent_inc(ntfs_index_context *icx)
static int ntfs_icx_parent_dec( ntfs_index_context *icx ) static int ntfs_icx_parent_dec( ntfs_index_context *icx )
{ {
icx->pindex--; icx->pindex--;
if (icx->pindex < 0) { if ( icx->pindex < 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "Corrupt index pointer (%d)", icx->pindex ); ntfs_log_perror( "Corrupt index pointer (%d)", icx->pindex );
return STATUS_ERROR; return STATUS_ERROR;
@ -677,21 +703,24 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
if (!key || key_len <= 0) { if ( !key || key_len <= 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "key: %p key_len: %d", key, key_len ); ntfs_log_perror( "key: %p key_len: %d", key, key_len );
return -1; return -1;
} }
ir = ntfs_ir_lookup( ni, icx->name, icx->name_len, &icx->actx ); ir = ntfs_ir_lookup( ni, icx->name, icx->name_len, &icx->actx );
if (!ir) { if ( !ir )
{
if ( errno == ENOENT ) if ( errno == ENOENT )
errno = EIO; errno = EIO;
return -1; return -1;
} }
icx->block_size = le32_to_cpu( ir->index_block_size ); icx->block_size = le32_to_cpu( ir->index_block_size );
if (icx->block_size < NTFS_BLOCK_SIZE) { if ( icx->block_size < NTFS_BLOCK_SIZE )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "Index block size (%d) is smaller than the " ntfs_log_perror( "Index block size (%d) is smaller than the "
"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE ); "sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE );
@ -704,7 +733,8 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
icx->vcn_size_bits = ni->vol->sector_size_bits; icx->vcn_size_bits = ni->vol->sector_size_bits;
/* get the appropriate collation function */ /* get the appropriate collation function */
icx->collate = ntfs_get_collate_function( ir->collation_rule ); icx->collate = ntfs_get_collate_function( ir->collation_rule );
if (!icx->collate) { if ( !icx->collate )
{
err = errno = EOPNOTSUPP; err = errno = EOPNOTSUPP;
ntfs_log_perror( "Unknown collation rule 0x%x", ntfs_log_perror( "Unknown collation rule 0x%x",
( unsigned )le32_to_cpu( ir->collation_rule ) ); ( unsigned )le32_to_cpu( ir->collation_rule ) );
@ -717,14 +747,16 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
* within the index block. * within the index block.
*/ */
ret = ntfs_ie_lookup( key, key_len, icx, &ir->index, &vcn, &ie ); ret = ntfs_ie_lookup( key, key_len, icx, &ir->index, &vcn, &ie );
if (ret == STATUS_ERROR) { if ( ret == STATUS_ERROR )
{
err = errno; err = errno;
goto err_out; goto err_out;
} }
icx->ir = ir; icx->ir = ir;
if (ret != STATUS_KEEP_SEARCHING) { if ( ret != STATUS_KEEP_SEARCHING )
{
/* STATUS_OK or STATUS_NOT_FOUND */ /* STATUS_OK or STATUS_NOT_FOUND */
err = errno; err = errno;
icx->is_in_root = TRUE; icx->is_in_root = TRUE;
@ -739,7 +771,8 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
goto err_out; goto err_out;
ib = ntfs_malloc( icx->block_size ); ib = ntfs_malloc( icx->block_size );
if (!ib) { if ( !ib )
{
err = errno; err = errno;
goto err_out; goto err_out;
} }
@ -747,7 +780,8 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
descend_into_child_node: descend_into_child_node:
icx->parent_vcn[icx->pindex] = old_vcn; icx->parent_vcn[icx->pindex] = old_vcn;
if (ntfs_icx_parent_inc(icx)) { if ( ntfs_icx_parent_inc( icx ) )
{
err = errno; err = errno;
goto err_out; goto err_out;
} }
@ -759,7 +793,8 @@ descend_into_child_node:
goto err_out; goto err_out;
ret = ntfs_ie_lookup( key, key_len, icx, &ib->index, &vcn, &ie ); ret = ntfs_ie_lookup( key, key_len, icx, &ib->index, &vcn, &ie );
if (ret != STATUS_KEEP_SEARCHING) { if ( ret != STATUS_KEEP_SEARCHING )
{
err = errno; err = errno;
if ( ret == STATUS_ERROR ) if ( ret == STATUS_ERROR )
goto err_out; goto err_out;
@ -771,7 +806,8 @@ descend_into_child_node:
goto done; goto done;
} }
if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) { if ( ( ib->index.ih_flags & NODE_MASK ) == LEAF_NODE )
{
ntfs_log_error( "Index entry with child node found in a leaf " ntfs_log_error( "Index entry with child node found in a leaf "
"node in inode 0x%llx.\n", "node in inode 0x%llx.\n",
( unsigned long long )ni->mft_no ); ( unsigned long long )ni->mft_no );
@ -790,7 +826,8 @@ done:
icx->data = ( u8 * )ie + offsetof( INDEX_ENTRY, key ); icx->data = ( u8 * )ie + offsetof( INDEX_ENTRY, key );
icx->data_len = le16_to_cpu( ie->key_length ); icx->data_len = le16_to_cpu( ie->key_length );
ntfs_log_trace( "Done.\n" ); ntfs_log_trace( "Done.\n" );
if (err) { if ( err )
{
errno = err; errno = err;
return -1; return -1;
} }
@ -843,7 +880,8 @@ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih)
ie = ie_start = ntfs_ie_get_first( ih ); ie = ie_start = ntfs_ie_get_first( ih );
ie_end = ( u8 * )ntfs_ie_get_end( ih ); ie_end = ( u8 * )ntfs_ie_get_end( ih );
while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) { while ( ( u8 * )ie < ie_end && !ntfs_ie_end( ie ) )
{
ie = ntfs_ie_get_next( ie ); ie = ntfs_ie_get_next( ie );
i++; i++;
} }
@ -883,7 +921,8 @@ static int ntfs_ibm_add(ntfs_index_context *icx)
*/ */
memset( bmp, 0, sizeof( bmp ) ); memset( bmp, 0, sizeof( bmp ) );
if ( ntfs_attr_add( icx->ni, AT_BITMAP, icx->name, icx->name_len, if ( ntfs_attr_add( icx->ni, AT_BITMAP, icx->name, icx->name_len,
bmp, sizeof(bmp))) { bmp, sizeof( bmp ) ) )
{
ntfs_log_perror( "Failed to add AT_BITMAP" ); ntfs_log_perror( "Failed to add AT_BITMAP" );
return STATUS_ERROR; return STATUS_ERROR;
} }
@ -903,21 +942,26 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
ntfs_log_trace( "%s vcn: %lld\n", set ? "set" : "clear", ( long long )vcn ); ntfs_log_trace( "%s vcn: %lld\n", set ? "set" : "clear", ( long long )vcn );
na = ntfs_attr_open( icx->ni, AT_BITMAP, icx->name, icx->name_len ); na = ntfs_attr_open( icx->ni, AT_BITMAP, icx->name, icx->name_len );
if (!na) { if ( !na )
{
ntfs_log_perror( "Failed to open $BITMAP attribute" ); ntfs_log_perror( "Failed to open $BITMAP attribute" );
return -1; return -1;
} }
if (set) { if ( set )
if (na->data_size < bpos + 1) { {
if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) { if ( na->data_size < bpos + 1 )
{
if ( ntfs_attr_truncate( na, ( na->data_size + 8 ) & ~7 ) )
{
ntfs_log_perror( "Failed to truncate AT_BITMAP" ); ntfs_log_perror( "Failed to truncate AT_BITMAP" );
goto err_na; goto err_na;
} }
} }
} }
if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) { if ( ntfs_attr_pread( na, bpos, 1, &byte ) != 1 )
{
ntfs_log_perror( "Failed to read $BITMAP" ); ntfs_log_perror( "Failed to read $BITMAP" );
goto err_na; goto err_na;
} }
@ -927,7 +971,8 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
else else
byte &= ~bit; byte &= ~bit;
if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) { if ( ntfs_attr_pwrite( na, bpos, 1, &byte ) != 1 )
{
ntfs_log_perror( "Failed to write $Bitmap" ); ntfs_log_perror( "Failed to write $Bitmap" );
goto err_na; goto err_na;
} }
@ -962,13 +1007,16 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx)
if ( !bm ) if ( !bm )
return ( VCN ) - 1; return ( VCN ) - 1;
for (byte = 0; byte < size; byte++) { for ( byte = 0; byte < size; byte++ )
{
if ( bm[byte] == 255 ) if ( bm[byte] == 255 )
continue; continue;
for (bit = 0; bit < 8; bit++) { for ( bit = 0; bit < 8; bit++ )
if (!(bm[byte] & (1 << bit))) { {
if ( !( bm[byte] & ( 1 << bit ) ) )
{
vcn = ntfs_ibm_pos_to_vcn( icx, byte * 8 + bit ); vcn = ntfs_ibm_pos_to_vcn( icx, byte * 8 + bit );
goto out; goto out;
} }
@ -1030,7 +1078,8 @@ static void ntfs_ir_nill(INDEX_ROOT *ir)
/* /*
* Move the index root termination entry forward * Move the index root termination entry forward
*/ */
if ((char *)ie_last > ies_start) { if ( ( char * )ie_last > ies_start )
{
memmove( ies_start, ( char * )ie_last, le16_to_cpu( ie_last->length ) ); memmove( ies_start, ( char * )ie_last, le16_to_cpu( ie_last->length ) );
ie_last = ( INDEX_ENTRY * )ies_start; ie_last = ( INDEX_ENTRY * )ies_start;
} }
@ -1098,10 +1147,12 @@ static int ntfs_ia_add(ntfs_index_context *icx)
if ( ntfs_ibm_add( icx ) ) if ( ntfs_ibm_add( icx ) )
return -1; return -1;
if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) { if ( !ntfs_attr_exist( icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len ) )
{
if ( ntfs_attr_add( icx->ni, AT_INDEX_ALLOCATION, icx->name, if ( ntfs_attr_add( icx->ni, AT_INDEX_ALLOCATION, icx->name,
icx->name_len, NULL, 0)) { icx->name_len, NULL, 0 ) )
{
ntfs_log_perror( "Failed to add AT_INDEX_ALLOCATION" ); ntfs_log_perror( "Failed to add AT_INDEX_ALLOCATION" );
return -1; return -1;
} }
@ -1142,7 +1193,8 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
goto clear_bmp; goto clear_bmp;
ib = ntfs_ir_to_ib( ir, new_ib_vcn ); ib = ntfs_ir_to_ib( ir, new_ib_vcn );
if (ib == NULL) { if ( ib == NULL )
{
ntfs_log_perror( "Failed to move index root to index block" ); ntfs_log_perror( "Failed to move index root to index block" );
goto clear_bmp; goto clear_bmp;
} }
@ -1200,7 +1252,8 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
na = ntfs_attr_open( icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len ); na = ntfs_attr_open( icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len );
if (!na) { if ( !na )
{
ntfs_log_perror( "Failed to open INDEX_ROOT" ); ntfs_log_perror( "Failed to open INDEX_ROOT" );
return STATUS_ERROR; return STATUS_ERROR;
} }
@ -1209,7 +1262,8 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
* INDEX_BLOCK, so ENOSPC isn't a real error. * INDEX_BLOCK, so ENOSPC isn't a real error.
*/ */
ret = ntfs_attr_truncate( na, data_size + offsetof( INDEX_ROOT, index ) ); ret = ntfs_attr_truncate( na, data_size + offsetof( INDEX_ROOT, index ) );
if (ret == STATUS_OK) { if ( ret == STATUS_OK )
{
icx->ir = ntfs_ir_lookup2( icx->ni, icx->name, icx->name_len ); icx->ir = ntfs_ir_lookup2( icx->ni, icx->name, icx->name_len );
if ( !icx->ir ) if ( !icx->ir )
@ -1217,7 +1271,8 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
icx->ir->index.allocated_size = cpu_to_le32( data_size ); icx->ir->index.allocated_size = cpu_to_le32( data_size );
} else if (ret == STATUS_ERROR) }
else if ( ret == STATUS_ERROR )
ntfs_log_perror( "Failed to truncate INDEX_ROOT" ); ntfs_log_perror( "Failed to truncate INDEX_ROOT" );
ntfs_attr_close( na ); ntfs_attr_close( na );
@ -1237,7 +1292,8 @@ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
ret = ntfs_ir_truncate( icx, data_size ); ret = ntfs_ir_truncate( icx, data_size );
if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { if ( ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT )
{
ret = ntfs_ir_reparent( icx ); ret = ntfs_ir_reparent( icx );
if ( ret == STATUS_OK ) if ( ret == STATUS_OK )
@ -1364,7 +1420,8 @@ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn)
idx_size = le32_to_cpu( ib->index.index_length ); idx_size = le32_to_cpu( ib->index.index_length );
allocated_size = le32_to_cpu( ib->index.allocated_size ); allocated_size = le32_to_cpu( ib->index.allocated_size );
/* FIXME: sizeof(VCN) should be included only if ie has no VCN */ /* FIXME: sizeof(VCN) should be included only if ie has no VCN */
if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) { if ( idx_size + le16_to_cpu( ie->length ) + sizeof( VCN ) > allocated_size )
{
err = ntfs_ib_split( icx, ib ); err = ntfs_ib_split( icx, ib );
if ( err == STATUS_OK ) if ( err == STATUS_OK )
err = STATUS_KEEP_SEARCHING; err = STATUS_KEEP_SEARCHING;
@ -1405,7 +1462,8 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
if ( new_vcn == -1 ) if ( new_vcn == -1 )
return STATUS_ERROR; return STATUS_ERROR;
if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) { if ( ntfs_ib_copy_tail( icx, ib, median, new_vcn ) )
{
ntfs_ibm_clear( icx, new_vcn ); ntfs_ibm_clear( icx, new_vcn );
return STATUS_ERROR; return STATUS_ERROR;
} }
@ -1415,7 +1473,8 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
else else
ret = ntfs_ib_insert( icx, median, new_vcn ); ret = ntfs_ib_insert( icx, median, new_vcn );
if (ret != STATUS_OK) { if ( ret != STATUS_OK )
{
ntfs_ibm_clear( icx, new_vcn ); ntfs_ibm_clear( icx, new_vcn );
return ret; return ret;
} }
@ -1441,14 +1500,17 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
*/ */
#endif #endif
while (1) { while ( 1 )
{
if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) { if ( !ntfs_index_lookup( &ie->key, le16_to_cpu( ie->key_length ), icx ) )
{
errno = EEXIST; errno = EEXIST;
ntfs_log_perror( "Index already have such entry" ); ntfs_log_perror( "Index already have such entry" );
goto err_out; goto err_out;
} }
if (errno != ENOENT) { if ( errno != ENOENT )
{
ntfs_log_perror( "Failed to find place for new entry" ); ntfs_log_perror( "Failed to find place for new entry" );
goto err_out; goto err_out;
} }
@ -1467,10 +1529,13 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
ntfs_log_trace( "index block sizes: allocated: %d needed: %d\n", ntfs_log_trace( "index block sizes: allocated: %d needed: %d\n",
allocated_size, new_size ); allocated_size, new_size );
if (icx->is_in_root) { if ( icx->is_in_root )
{
if ( ntfs_ir_make_space( icx, new_size ) == STATUS_ERROR ) if ( ntfs_ir_make_space( icx, new_size ) == STATUS_ERROR )
goto err_out; goto err_out;
} else { }
else
{
if ( ntfs_ib_split( icx, icx->ib ) == STATUS_ERROR ) if ( ntfs_ib_split( icx, icx->ib ) == STATUS_ERROR )
goto err_out; goto err_out;
} }
@ -1504,7 +1569,8 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
if (!ni || !fn) { if ( !ni || !fn )
{
ntfs_log_error( "Invalid arguments.\n" ); ntfs_log_error( "Invalid arguments.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -1552,8 +1618,7 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih,
if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT ) if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
ntfs_inode_mark_dirty( icx->actx->ntfs_ino ); ntfs_inode_mark_dirty( icx->actx->ntfs_ino );
else else if ( ntfs_ib_write( icx, ib ) )
if (ntfs_ib_write(icx, ib))
goto out; goto out;
ntfs_index_ctx_reinit( icx ); ntfs_index_ctx_reinit( icx );
@ -1621,7 +1686,8 @@ static int ntfs_index_rm_leaf(ntfs_index_context *icx)
if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT ) if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
parent_ih = &icx->ir->index; parent_ih = &icx->ir->index;
else { else
{
ib = ntfs_malloc( icx->block_size ); ib = ntfs_malloc( icx->block_size );
if ( !ib ) if ( !ib )
return STATUS_ERROR; return STATUS_ERROR;
@ -1633,14 +1699,17 @@ static int ntfs_index_rm_leaf(ntfs_index_context *icx)
} }
ie = ntfs_ie_get_by_pos( parent_ih, ntfs_icx_parent_pos( icx ) ); ie = ntfs_ie_get_by_pos( parent_ih, ntfs_icx_parent_pos( icx ) );
if (!ntfs_ie_end(ie)) { if ( !ntfs_ie_end( ie ) )
{
ret = ntfs_ih_takeout( icx, parent_ih, ie, ib ); ret = ntfs_ih_takeout( icx, parent_ih, ie, ib );
goto out; goto out;
} }
if (ntfs_ih_zero_entry(parent_ih)) { if ( ntfs_ih_zero_entry( parent_ih ) )
{
if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) { if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
{
ntfs_ir_leafify( icx, parent_ih ); ntfs_ir_leafify( icx, parent_ih );
goto ok; goto ok;
} }
@ -1670,7 +1739,8 @@ static int ntfs_index_rm_node(ntfs_index_context *icx)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
if (!icx->ia_na) { if ( !icx->ia_na )
{
icx->ia_na = ntfs_ia_open( icx, icx->ni ); icx->ia_na = ntfs_ia_open( icx, icx->ni );
if ( !icx->ia_na ) if ( !icx->ia_na )
return STATUS_ERROR; return STATUS_ERROR;
@ -1699,7 +1769,8 @@ descend:
if ( ( ib->index.ih_flags & NODE_MASK ) == INDEX_NODE ) if ( ( ib->index.ih_flags & NODE_MASK ) == INDEX_NODE )
goto descend; goto descend;
if (ntfs_ih_zero_entry(&ib->index)) { if ( ntfs_ih_zero_entry( &ib->index ) )
{
errno = EIO; errno = EIO;
ntfs_log_perror( "Empty index block" ); ntfs_log_perror( "Empty index block" );
goto out; goto out;
@ -1721,8 +1792,10 @@ descend:
delta = le16_to_cpu( ie->length ) - le16_to_cpu( icx->entry->length ); delta = le16_to_cpu( ie->length ) - le16_to_cpu( icx->entry->length );
new_size = le32_to_cpu( ih->index_length ) + delta; new_size = le32_to_cpu( ih->index_length ) + delta;
if (delta > 0) { if ( delta > 0 )
if (icx->is_in_root) { {
if ( icx->is_in_root )
{
ret = ntfs_ir_make_space( icx, new_size ); ret = ntfs_ir_make_space( icx, new_size );
if ( ret != STATUS_OK ) if ( ret != STATUS_OK )
goto out2; goto out2;
@ -1730,7 +1803,9 @@ descend:
ih = &icx->ir->index; ih = &icx->ir->index;
entry = ntfs_ie_get_by_pos( ih, entry_pos ); entry = ntfs_ie_get_by_pos( ih, entry_pos );
} else if (new_size > le32_to_cpu(ih->allocated_size)) { }
else if ( new_size > le32_to_cpu( ih->allocated_size ) )
{
icx->pindex = pindex; icx->pindex = pindex;
ret = ntfs_ib_split( icx, icx->ib ); ret = ntfs_ib_split( icx, icx->ib );
if ( ret == STATUS_OK ) if ( ret == STATUS_OK )
@ -1742,20 +1817,22 @@ descend:
ntfs_ie_delete( ih, entry ); ntfs_ie_delete( ih, entry );
ntfs_ie_insert( ih, ie, entry ); ntfs_ie_insert( ih, ie, entry );
if (icx->is_in_root) { if ( icx->is_in_root )
{
if ( ntfs_ir_truncate( icx, new_size ) ) if ( ntfs_ir_truncate( icx, new_size ) )
goto out2; goto out2;
} else }
if (ntfs_icx_ib_write(icx)) else if ( ntfs_icx_ib_write( icx ) )
goto out2; goto out2;
ntfs_ie_delete( &ib->index, ie_succ ); ntfs_ie_delete( &ib->index, ie_succ );
if (ntfs_ih_zero_entry(&ib->index)) { if ( ntfs_ih_zero_entry( &ib->index ) )
{
if ( ntfs_index_rm_leaf( icx ) ) if ( ntfs_index_rm_leaf( icx ) )
goto out2; goto out2;
} else }
if (ntfs_ib_write(icx, ib)) else if ( ntfs_ib_write( icx, ib ) )
goto out2; goto out2;
ret = STATUS_OK; ret = STATUS_OK;
@ -1784,7 +1861,8 @@ int ntfs_index_rm(ntfs_index_context *icx)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) { if ( !icx || ( !icx->ib && !icx->ir ) || ntfs_ie_end( icx->entry ) )
{
ntfs_log_error( "Invalid arguments.\n" ); ntfs_log_error( "Invalid arguments.\n" );
errno = EINVAL; errno = EINVAL;
goto err_out; goto err_out;
@ -1794,22 +1872,28 @@ int ntfs_index_rm(ntfs_index_context *icx)
else else
ih = &icx->ib->index; ih = &icx->ib->index;
if (icx->entry->ie_flags & INDEX_ENTRY_NODE) { if ( icx->entry->ie_flags & INDEX_ENTRY_NODE )
{
ret = ntfs_index_rm_node( icx ); ret = ntfs_index_rm_node( icx );
} else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { }
else if ( icx->is_in_root || !ntfs_ih_one_entry( ih ) )
{
ntfs_ie_delete( ih, icx->entry ); ntfs_ie_delete( ih, icx->entry );
if (icx->is_in_root) { if ( icx->is_in_root )
{
err = ntfs_ir_truncate( icx, le32_to_cpu( ih->index_length ) ); err = ntfs_ir_truncate( icx, le32_to_cpu( ih->index_length ) );
if ( err != STATUS_OK ) if ( err != STATUS_OK )
goto err_out; goto err_out;
} else }
if (ntfs_icx_ib_write(icx)) else if ( ntfs_icx_ib_write( icx ) )
goto err_out; goto err_out;
} else { }
else
{
if ( ntfs_index_rm_leaf( icx ) ) if ( ntfs_index_rm_leaf( icx ) )
goto err_out; goto err_out;
} }
@ -1830,14 +1914,16 @@ int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
if ( !icx ) if ( !icx )
return -1; return -1;
while (1) { while ( 1 )
{
if ( ntfs_index_lookup( key, keylen, icx ) ) if ( ntfs_index_lookup( key, keylen, icx ) )
goto err_out; goto err_out;
if ( ( ( ( FILE_NAME_ATTR * )icx->data )->file_attributes & if ( ( ( ( FILE_NAME_ATTR * )icx->data )->file_attributes &
FILE_ATTR_REPARSE_POINT ) FILE_ATTR_REPARSE_POINT )
&& !ntfs_possible_symlink(ni)) { && !ntfs_possible_symlink( ni ) )
{
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
goto err_out; goto err_out;
} }
@ -1910,9 +1996,11 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
s64 vcn; s64 vcn;
entry = ie; entry = ie;
do { do
{
vcn = ntfs_ie_get_vcn( entry ); vcn = ntfs_ie_get_vcn( entry );
if (ictx->is_in_root) { if ( ictx->is_in_root )
{
/* down from level zero */ /* down from level zero */
@ -1920,7 +2008,9 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
ictx->ib = ( INDEX_BLOCK* )ntfs_malloc( ictx->block_size ); ictx->ib = ( INDEX_BLOCK* )ntfs_malloc( ictx->block_size );
ictx->pindex = 1; ictx->pindex = 1;
ictx->is_in_root = FALSE; ictx->is_in_root = FALSE;
} else { }
else
{
/* down from non-zero level */ /* down from non-zero level */
@ -1928,12 +2018,15 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
} }
ictx->parent_pos[ictx->pindex] = 0; ictx->parent_pos[ictx->pindex] = 0;
ictx->parent_vcn[ictx->pindex] = vcn; ictx->parent_vcn[ictx->pindex] = vcn;
if (!ntfs_ib_read(ictx,vcn,ictx->ib)) { if ( !ntfs_ib_read( ictx, vcn, ictx->ib ) )
{
ictx->entry = ntfs_ie_get_first( &ictx->ib->index ); ictx->entry = ntfs_ie_get_first( &ictx->ib->index );
entry = ictx->entry; entry = ictx->entry;
} else }
else
entry = ( INDEX_ENTRY* )NULL; entry = ( INDEX_ENTRY* )NULL;
} while (entry && (entry->ie_flags & INDEX_ENTRY_NODE)); }
while ( entry && ( entry->ie_flags & INDEX_ENTRY_NODE ) );
return ( entry ); return ( entry );
} }
@ -1950,10 +2043,13 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
s64 vcn; s64 vcn;
entry = ie; entry = ie;
if (ictx->pindex > 0) { if ( ictx->pindex > 0 )
do { {
do
{
ictx->pindex--; ictx->pindex--;
if (!ictx->pindex) { if ( !ictx->pindex )
{
/* we have reached the root */ /* we have reached the root */
@ -1972,20 +2068,26 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
ictx->parent_pos[ictx->pindex] ); ictx->parent_pos[ictx->pindex] );
else else
entry = ( INDEX_ENTRY* )NULL; entry = ( INDEX_ENTRY* )NULL;
} else { }
else
{
/* up into non-root node */ /* up into non-root node */
vcn = ictx->parent_vcn[ictx->pindex]; vcn = ictx->parent_vcn[ictx->pindex];
if (!ntfs_ib_read(ictx,vcn,ictx->ib)) { if ( !ntfs_ib_read( ictx, vcn, ictx->ib ) )
{
entry = ntfs_ie_get_by_pos( entry = ntfs_ie_get_by_pos(
&ictx->ib->index, &ictx->ib->index,
ictx->parent_pos[ictx->pindex] ); ictx->parent_pos[ictx->pindex] );
} else }
else
entry = ( INDEX_ENTRY* )NULL; entry = ( INDEX_ENTRY* )NULL;
} }
ictx->entry = entry; ictx->entry = entry;
} while (entry && (ictx->pindex > 0) }
while ( entry && ( ictx->pindex > 0 )
&& ( entry->ie_flags & INDEX_ENTRY_END ) ); && ( entry->ie_flags & INDEX_ENTRY_END ) );
} else }
else
entry = ( INDEX_ENTRY* )NULL; entry = ( INDEX_ENTRY* )NULL;
return ( entry ); return ( entry );
} }
@ -2030,7 +2132,8 @@ INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx)
if ( ie->ie_flags & INDEX_ENTRY_END ) if ( ie->ie_flags & INDEX_ENTRY_END )
next = ntfs_index_walk_up( ie, ictx ); next = ntfs_index_walk_up( ie, ictx );
else { else
{
/* /*
* get next entry in same node * get next entry in same node
* there is always one after any entry with data * there is always one after any entry with data
@ -2042,13 +2145,17 @@ INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx)
/* walk down if it has a subnode */ /* walk down if it has a subnode */
if (flags & INDEX_ENTRY_NODE) { if ( flags & INDEX_ENTRY_NODE )
{
next = ntfs_index_walk_down( next, ictx ); next = ntfs_index_walk_down( next, ictx );
} else { }
else
{
/* walk up it has no subnode, nor data */ /* walk up it has no subnode, nor data */
if (flags & INDEX_ENTRY_END) { if ( flags & INDEX_ENTRY_END )
{
next = ntfs_index_walk_up( next, ictx ); next = ntfs_index_walk_up( next, ictx );
} }
} }

View File

@ -112,7 +112,8 @@ typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
* the call to ntfs_index_ctx_put() to ensure that the changes are written * the call to ntfs_index_ctx_put() to ensure that the changes are written
* to disk. * to disk.
*/ */
typedef struct { typedef struct
{
ntfs_inode *ni; ntfs_inode *ni;
ntfschar *name; ntfschar *name;
u32 name_len; u32 name_len;

View File

@ -166,7 +166,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
int olderrno; int olderrno;
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) ); ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
if (!vol) { if ( !vol )
{
errno = EINVAL; errno = EINVAL;
goto out; goto out;
} }
@ -175,7 +176,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
goto out; goto out;
if ( ntfs_file_record_read( vol, mref, &ni->mrec, NULL ) ) if ( ntfs_file_record_read( vol, mref, &ni->mrec, NULL ) )
goto err_out; goto err_out;
if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) { if ( !( ni->mrec->flags & MFT_RECORD_IN_USE ) )
{
errno = ENOENT; errno = ENOENT;
goto err_out; goto err_out;
} }
@ -185,7 +187,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
goto err_out; goto err_out;
/* Receive some basic information about inode. */ /* Receive some basic information about inode. */
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED, if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { 0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
if ( !ni->mrec->base_mft_record ) if ( !ni->mrec->base_mft_record )
ntfs_log_perror( "No STANDARD_INFORMATION in base record" ntfs_log_perror( "No STANDARD_INFORMATION in base record"
" %lld", ( long long )MREF( mref ) ); " %lld", ( long long )MREF( mref ) );
@ -201,13 +204,16 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
/* JPA insert v3 extensions if present */ /* JPA insert v3 extensions if present */
/* length may be seen as 72 (v1.x) or 96 (v3.x) */ /* length may be seen as 72 (v1.x) or 96 (v3.x) */
lthle = ctx->attr->length; lthle = ctx->attr->length;
if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) { if ( le32_to_cpu( lthle ) > sizeof( STANDARD_INFORMATION ) )
{
set_nino_flag( ni, v3_Extensions ); set_nino_flag( ni, v3_Extensions );
ni->owner_id = std_info->owner_id; ni->owner_id = std_info->owner_id;
ni->security_id = std_info->security_id; ni->security_id = std_info->security_id;
ni->quota_charged = std_info->quota_charged; ni->quota_charged = std_info->quota_charged;
ni->usn = std_info->usn; ni->usn = std_info->usn;
} else { }
else
{
clear_nino_flag( ni, v3_Extensions ); clear_nino_flag( ni, v3_Extensions );
ni->owner_id = const_cpu_to_le32( 0 ); ni->owner_id = const_cpu_to_le32( 0 );
ni->security_id = const_cpu_to_le32( 0 ); ni->security_id = const_cpu_to_le32( 0 );
@ -215,7 +221,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
/* Set attribute list information. */ /* Set attribute list information. */
olderrno = errno; olderrno = errno;
if ( ntfs_attr_lookup( AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, if ( ntfs_attr_lookup( AT_ATTRIBUTE_LIST, AT_UNNAMED, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) { CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
if ( errno != ENOENT ) if ( errno != ENOENT )
goto put_err_out; goto put_err_out;
/* Attribute list attribute does not present. */ /* Attribute list attribute does not present. */
@ -227,7 +234,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
l = ntfs_get_attribute_value_length( ctx->attr ); l = ntfs_get_attribute_value_length( ctx->attr );
if ( !l ) if ( !l )
goto put_err_out; goto put_err_out;
if (l > 0x40000) { if ( l > 0x40000 )
{
errno = EIO; errno = EIO;
ntfs_log_perror( "Too large attrlist attribute (%lld), inode " ntfs_log_perror( "Too large attrlist attribute (%lld), inode "
"%lld", ( long long )l, ( long long )MREF( mref ) ); "%lld", ( long long )l, ( long long )MREF( mref ) );
@ -240,7 +248,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
l = ntfs_get_attribute_value( vol, ctx->attr, ni->attr_list ); l = ntfs_get_attribute_value( vol, ctx->attr, ni->attr_list );
if ( !l ) if ( !l )
goto put_err_out; goto put_err_out;
if (l != ni->attr_list_size) { if ( l != ni->attr_list_size )
{
errno = EIO; errno = EIO;
ntfs_log_perror( "Unexpected attrlist size (%lld <> %u), inode " ntfs_log_perror( "Unexpected attrlist size (%lld <> %u), inode "
"%lld", ( long long )l, ni->attr_list_size, "%lld", ( long long )l, ni->attr_list_size,
@ -249,15 +258,19 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
} }
get_size: get_size:
olderrno = errno; olderrno = errno;
if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if ( ntfs_attr_lookup( AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx ) )
{
if ( errno != ENOENT ) if ( errno != ENOENT )
goto put_err_out; goto put_err_out;
/* Directory or special file. */ /* Directory or special file. */
/* restore previous errno to avoid misinterpretation */ /* restore previous errno to avoid misinterpretation */
errno = olderrno; errno = olderrno;
ni->data_size = ni->allocated_size = 0; ni->data_size = ni->allocated_size = 0;
} else { }
if (ctx->attr->non_resident) { else
{
if ( ctx->attr->non_resident )
{
ni->data_size = sle64_to_cpu( ctx->attr->data_size ); ni->data_size = sle64_to_cpu( ctx->attr->data_size );
if ( ctx->attr->flags & if ( ctx->attr->flags &
( ATTR_IS_COMPRESSED | ATTR_IS_SPARSE ) ) ( ATTR_IS_COMPRESSED | ATTR_IS_SPARSE ) )
@ -266,7 +279,9 @@ get_size:
else else
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
ctx->attr->allocated_size ); ctx->attr->allocated_size );
} else { }
else
{
ni->data_size = le32_to_cpu( ctx->attr->value_length ); ni->data_size = le32_to_cpu( ctx->attr->value_length );
ni->allocated_size = ( ni->data_size + 7 ) & ~7; ni->allocated_size = ( ni->data_size + 7 ) & ~7;
} }
@ -320,23 +335,30 @@ int ntfs_inode_real_close(ntfs_inode *ni)
ntfs_log_enter( "Entering for inode %lld\n", ( long long )ni->mft_no ); ntfs_log_enter( "Entering for inode %lld\n", ( long long )ni->mft_no );
/* If we have dirty metadata, write it out. */ /* If we have dirty metadata, write it out. */
if (NInoDirty(ni) || NInoAttrListDirty(ni)) { if ( NInoDirty( ni ) || NInoAttrListDirty( ni ) )
if (ntfs_inode_sync(ni)) { {
if ( ntfs_inode_sync( ni ) )
{
if ( errno != EIO ) if ( errno != EIO )
errno = EBUSY; errno = EBUSY;
goto err; goto err;
} }
} }
/* Is this a base inode with mapped extent inodes? */ /* Is this a base inode with mapped extent inodes? */
if (ni->nr_extents > 0) { if ( ni->nr_extents > 0 )
while (ni->nr_extents > 0) { {
if (ntfs_inode_real_close(ni->extent_nis[0])) { while ( ni->nr_extents > 0 )
{
if ( ntfs_inode_real_close( ni->extent_nis[0] ) )
{
if ( errno != EIO ) if ( errno != EIO )
errno = EBUSY; errno = EBUSY;
goto err; goto err;
} }
} }
} else if (ni->nr_extents == -1) { }
else if ( ni->nr_extents == -1 )
{
ntfs_inode **tmp_nis; ntfs_inode **tmp_nis;
ntfs_inode *base_ni; ntfs_inode *base_ni;
s32 i; s32 i;
@ -346,7 +368,8 @@ int ntfs_inode_real_close(ntfs_inode *ni)
* base inode before destroying it. * base inode before destroying it.
*/ */
base_ni = ni->base_ni; base_ni = ni->base_ni;
for (i = 0; i < base_ni->nr_extents; ++i) { for ( i = 0; i < base_ni->nr_extents; ++i )
{
tmp_nis = base_ni->extent_nis; tmp_nis = base_ni->extent_nis;
if ( tmp_nis[i] != ni ) if ( tmp_nis[i] != ni )
continue; continue;
@ -355,7 +378,8 @@ int ntfs_inode_real_close(ntfs_inode *ni)
( base_ni->nr_extents - i - 1 ) * ( base_ni->nr_extents - i - 1 ) *
sizeof( ntfs_inode * ) ); sizeof( ntfs_inode * ) );
/* Buffer should be for multiple of four extents. */ /* Buffer should be for multiple of four extents. */
if ((--base_ni->nr_extents) & 3) { if ( ( --base_ni->nr_extents ) & 3 )
{
i = -1; i = -1;
break; break;
} }
@ -363,14 +387,17 @@ int ntfs_inode_real_close(ntfs_inode *ni)
* ElectricFence is unhappy with realloc(x,0) as free(x) * ElectricFence is unhappy with realloc(x,0) as free(x)
* thus we explicitly separate these two cases. * thus we explicitly separate these two cases.
*/ */
if (base_ni->nr_extents) { if ( base_ni->nr_extents )
{
/* Resize the memory buffer. */ /* Resize the memory buffer. */
tmp_nis = realloc( tmp_nis, base_ni->nr_extents * tmp_nis = realloc( tmp_nis, base_ni->nr_extents *
sizeof( ntfs_inode * ) ); sizeof( ntfs_inode * ) );
/* Ignore errors, they don't really matter. */ /* Ignore errors, they don't really matter. */
if ( tmp_nis ) if ( tmp_nis )
base_ni->extent_nis = tmp_nis; base_ni->extent_nis = tmp_nis;
} else if (tmp_nis) { }
else if ( tmp_nis )
{
free( tmp_nis ); free( tmp_nis );
base_ni->extent_nis = ( ntfs_inode** )NULL; base_ni->extent_nis = ( ntfs_inode** )NULL;
} }
@ -473,12 +500,15 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
item.varsize = 0; item.varsize = 0;
cached = ( struct CACHED_NIDATA* )ntfs_fetch_cache( vol->nidata_cache, cached = ( struct CACHED_NIDATA* )ntfs_fetch_cache( vol->nidata_cache,
GENERIC( &item ), idata_cache_compare ); GENERIC( &item ), idata_cache_compare );
if (cached) { if ( cached )
{
ni = cached->ni; ni = cached->ni;
/* do not keep open entries in cache */ /* do not keep open entries in cache */
ntfs_remove_cache( vol->nidata_cache, ntfs_remove_cache( vol->nidata_cache,
( struct CACHED_GENERIC* )cached, 0 ); ( struct CACHED_GENERIC* )cached, 0 );
} else { }
else
{
ni = ntfs_inode_real_open( vol, mref ); ni = ntfs_inode_real_open( vol, mref );
} }
#else #else
@ -504,24 +534,29 @@ int ntfs_inode_close(ntfs_inode *ni)
BOOL dirty; BOOL dirty;
struct CACHED_NIDATA item; struct CACHED_NIDATA item;
if (ni) { if ( ni )
{
debug_double_inode( ni->mft_no, 0 ); debug_double_inode( ni->mft_no, 0 );
/* do not cache system files : could lead to double entries */ /* do not cache system files : could lead to double entries */
if ( ni->vol && ni->vol->nidata_cache if ( ni->vol && ni->vol->nidata_cache
&& ( ( ni->mft_no == FILE_root ) && ( ( ni->mft_no == FILE_root )
|| ( ( ni->mft_no >= FILE_first_user ) || ( ( ni->mft_no >= FILE_first_user )
&& !(ni->mrec->flags & MFT_RECORD_IS_4)))) { && !( ni->mrec->flags & MFT_RECORD_IS_4 ) ) ) )
{
/* If we have dirty metadata, write it out. */ /* If we have dirty metadata, write it out. */
dirty = NInoDirty( ni ) || NInoAttrListDirty( ni ); dirty = NInoDirty( ni ) || NInoAttrListDirty( ni );
if (dirty) { if ( dirty )
{
res = ntfs_inode_sync( ni ); res = ntfs_inode_sync( ni );
/* do a real close if sync failed */ /* do a real close if sync failed */
if ( res ) if ( res )
ntfs_inode_real_close( ni ); ntfs_inode_real_close( ni );
} else }
else
res = 0; res = 0;
if (!res) { if ( !res )
{
/* feed idata into cache */ /* feed idata into cache */
item.inum = ni->mft_no; item.inum = ni->mft_no;
item.ni = ni; item.ni = ni;
@ -531,11 +566,14 @@ int ntfs_inode_close(ntfs_inode *ni)
ntfs_enter_cache( ni->vol->nidata_cache, ntfs_enter_cache( ni->vol->nidata_cache,
GENERIC( &item ), idata_cache_compare ); GENERIC( &item ), idata_cache_compare );
} }
} else { }
else
{
/* cache not ready or system file, really close */ /* cache not ready or system file, really close */
res = ntfs_inode_real_close( ni ); res = ntfs_inode_real_close( ni );
} }
} else }
else
res = 0; res = 0;
#else #else
res = ntfs_inode_real_close( ni ); res = ntfs_inode_real_close( ni );
@ -575,7 +613,8 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
ntfs_inode **extent_nis; ntfs_inode **extent_nis;
int i; int i;
if (!base_ni) { if ( !base_ni )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s", __FUNCTION__ ); ntfs_log_perror( "%s", __FUNCTION__ );
return NULL; return NULL;
@ -586,9 +625,11 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
( unsigned long long )base_ni->mft_no ); ( unsigned long long )base_ni->mft_no );
/* Is the extent inode already open and attached to the base inode? */ /* Is the extent inode already open and attached to the base inode? */
if (base_ni->nr_extents > 0) { if ( base_ni->nr_extents > 0 )
{
extent_nis = base_ni->extent_nis; extent_nis = base_ni->extent_nis;
for (i = 0; i < base_ni->nr_extents; i++) { for ( i = 0; i < base_ni->nr_extents; i++ )
{
u16 seq_no; u16 seq_no;
ni = extent_nis[i]; ni = extent_nis[i];
@ -597,7 +638,8 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
/* Verify the sequence number if given. */ /* Verify the sequence number if given. */
seq_no = MSEQNO_LE( mref ); seq_no = MSEQNO_LE( mref );
if ( seq_no && seq_no != le16_to_cpu( if ( seq_no && seq_no != le16_to_cpu(
ni->mrec->sequence_number)) { ni->mrec->sequence_number ) )
{
errno = EIO; errno = EIO;
ntfs_log_perror( "Found stale extent mft " ntfs_log_perror( "Found stale extent mft "
"reference mft=%lld", "reference mft=%lld",
@ -617,13 +659,15 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
ni->nr_extents = -1; ni->nr_extents = -1;
ni->base_ni = base_ni; ni->base_ni = base_ni;
/* Attach extent inode to base inode, reallocating memory if needed. */ /* Attach extent inode to base inode, reallocating memory if needed. */
if (!(base_ni->nr_extents & 3)) { if ( !( base_ni->nr_extents & 3 ) )
{
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * ); i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
extent_nis = ntfs_malloc( i ); extent_nis = ntfs_malloc( i );
if ( !extent_nis ) if ( !extent_nis )
goto err_out; goto err_out;
if (base_ni->nr_extents) { if ( base_ni->nr_extents )
{
memcpy( extent_nis, base_ni->extent_nis, memcpy( extent_nis, base_ni->extent_nis,
i - 4 * sizeof( ntfs_inode * ) ); i - 4 * sizeof( ntfs_inode * ) );
free( base_ni->extent_nis ); free( base_ni->extent_nis );
@ -651,7 +695,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
ATTR_LIST_ENTRY *ale; ATTR_LIST_ENTRY *ale;
u64 prev_attached = 0; u64 prev_attached = 0;
if (!ni) { if ( !ni )
{
ntfs_log_trace( "Invalid arguments.\n" ); ntfs_log_trace( "Invalid arguments.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -666,7 +711,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
if ( !NInoAttrList( ni ) ) if ( !NInoAttrList( ni ) )
return 0; return 0;
if (!ni->attr_list) { if ( !ni->attr_list )
{
ntfs_log_trace( "Corrupt in-memory struct.\n" ); ntfs_log_trace( "Corrupt in-memory struct.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -675,10 +721,13 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
/* Walk through attribute list and attach all extents. */ /* Walk through attribute list and attach all extents. */
errno = 0; errno = 0;
ale = ( ATTR_LIST_ENTRY * )ni->attr_list; ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
while ((u8*)ale < ni->attr_list + ni->attr_list_size) { while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
{
if ( ni->mft_no != MREF_LE( ale->mft_reference ) && if ( ni->mft_no != MREF_LE( ale->mft_reference ) &&
prev_attached != MREF_LE(ale->mft_reference)) { prev_attached != MREF_LE( ale->mft_reference ) )
if (!ntfs_extent_inode_open(ni, ale->mft_reference)) { {
if ( !ntfs_extent_inode_open( ni, ale->mft_reference ) )
{
ntfs_log_trace( "Couldn't attach extent inode.\n" ); ntfs_log_trace( "Couldn't attach extent inode.\n" );
return -1; return -1;
} }
@ -708,7 +757,8 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
if ( !ctx ) if ( !ctx )
return -1; return -1;
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED, if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { 0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
ntfs_log_perror( "Failed to sync standard info (inode %lld)", ntfs_log_perror( "Failed to sync standard info (inode %lld)",
( long long )ni->mft_no ); ( long long )ni->mft_no );
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
@ -717,7 +767,8 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr + std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
le16_to_cpu( ctx->attr->value_offset ) ); le16_to_cpu( ctx->attr->value_offset ) );
std_info->file_attributes = ni->flags; std_info->file_attributes = ni->flags;
if (!test_nino_flag(ni, TimesSet)) { if ( !test_nino_flag( ni, TimesSet ) )
{
std_info->creation_time = ni->creation_time; std_info->creation_time = ni->creation_time;
std_info->last_data_change_time = ni->last_data_change_time; std_info->last_data_change_time = ni->last_data_change_time;
std_info->last_mft_change_time = ni->last_mft_change_time; std_info->last_mft_change_time = ni->last_mft_change_time;
@ -732,7 +783,8 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
&& ( lth <= sizeof( STANDARD_INFORMATION ) ) ) && ( lth <= sizeof( STANDARD_INFORMATION ) ) )
ntfs_log_error( "bad sync of standard information\n" ); ntfs_log_error( "bad sync of standard information\n" );
if (lth > sizeof(STANDARD_INFORMATION)) { if ( lth > sizeof( STANDARD_INFORMATION ) )
{
std_info->owner_id = ni->owner_id; std_info->owner_id = ni->owner_id;
std_info->security_id = ni->security_id; std_info->security_id = ni->security_id;
std_info->quota_charged = ni->quota_charged; std_info->quota_charged = ni->quota_charged;
@ -765,15 +817,18 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
ntfs_log_trace( "Entering for inode %lld\n", ( long long )ni->mft_no ); ntfs_log_trace( "Entering for inode %lld\n", ( long long )ni->mft_no );
ctx = ntfs_attr_get_search_ctx( ni, NULL ); ctx = ntfs_attr_get_search_ctx( ni, NULL );
if (!ctx) { if ( !ctx )
{
err = errno; err = errno;
goto err_out; goto err_out;
} }
/* Collect the reparse tag, if any */ /* Collect the reparse tag, if any */
reparse_tag = cpu_to_le32( 0 ); reparse_tag = cpu_to_le32( 0 );
if (ni->flags & FILE_ATTR_REPARSE_POINT) { if ( ni->flags & FILE_ATTR_REPARSE_POINT )
{
if ( !ntfs_attr_lookup( AT_REPARSE_POINT, NULL, if ( !ntfs_attr_lookup( AT_REPARSE_POINT, NULL,
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { 0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
rpp = ( REPARSE_POINT* )( ( u8 * )ctx->attr + rpp = ( REPARSE_POINT* )( ( u8 * )ctx->attr +
le16_to_cpu( ctx->attr->value_offset ) ); le16_to_cpu( ctx->attr->value_offset ) );
reparse_tag = rpp->reparse_tag; reparse_tag = rpp->reparse_tag;
@ -781,10 +836,12 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
} }
/* Walk through all FILE_NAME attributes and update them. */ /* Walk through all FILE_NAME attributes and update them. */
while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) { while ( !ntfs_attr_lookup( AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx ) )
{
fn = ( FILE_NAME_ATTR * )( ( u8 * )ctx->attr + fn = ( FILE_NAME_ATTR * )( ( u8 * )ctx->attr +
le16_to_cpu( ctx->attr->value_offset ) ); le16_to_cpu( ctx->attr->value_offset ) );
if (MREF_LE(fn->parent_directory) == ni->mft_no) { if ( MREF_LE( fn->parent_directory ) == ni->mft_no )
{
/* /*
* WARNING: We cheat here and obtain 2 attribute * WARNING: We cheat here and obtain 2 attribute
* search contexts for one inode (first we obtained * search contexts for one inode (first we obtained
@ -793,13 +850,14 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
* but will deadlock in the kernel. * but will deadlock in the kernel.
*/ */
index_ni = ni; index_ni = ni;
} else }
if (dir_ni) else if ( dir_ni )
index_ni = dir_ni; index_ni = dir_ni;
else else
index_ni = ntfs_inode_open( ni->vol, index_ni = ntfs_inode_open( ni->vol,
le64_to_cpu( fn->parent_directory ) ); le64_to_cpu( fn->parent_directory ) );
if (!index_ni) { if ( !index_ni )
{
if ( !err ) if ( !err )
err = errno; err = errno;
ntfs_log_perror( "Failed to open inode %lld with index", ntfs_log_perror( "Failed to open inode %lld with index",
@ -807,7 +865,8 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
continue; continue;
} }
ictx = ntfs_index_ctx_get( index_ni, NTFS_INDEX_I30, 4 ); ictx = ntfs_index_ctx_get( index_ni, NTFS_INDEX_I30, 4 );
if (!ictx) { if ( !ictx )
{
if ( !err ) if ( !err )
err = errno; err = errno;
ntfs_log_perror( "Failed to get index ctx, inode %lld", ntfs_log_perror( "Failed to get index ctx, inode %lld",
@ -817,8 +876,10 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
err = errno; err = errno;
continue; continue;
} }
if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { if ( ntfs_index_lookup( fn, sizeof( FILE_NAME_ATTR ), ictx ) )
if (!err) { {
if ( !err )
{
if ( errno == ENOENT ) if ( errno == ENOENT )
err = EIO; err = EIO;
else else
@ -839,18 +900,22 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
if ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) if ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
fnx->data_size = fnx->allocated_size fnx->data_size = fnx->allocated_size
= const_cpu_to_le64( 0 ); = const_cpu_to_le64( 0 );
else { else
{
fnx->allocated_size = cpu_to_sle64( ni->allocated_size ); fnx->allocated_size = cpu_to_sle64( ni->allocated_size );
fnx->data_size = cpu_to_sle64( ni->data_size ); fnx->data_size = cpu_to_sle64( ni->data_size );
} }
/* update or clear the reparse tag in the index */ /* update or clear the reparse tag in the index */
fnx->reparse_point_tag = reparse_tag; fnx->reparse_point_tag = reparse_tag;
if (!test_nino_flag(ni, TimesSet)) { if ( !test_nino_flag( ni, TimesSet ) )
{
fnx->creation_time = ni->creation_time; fnx->creation_time = ni->creation_time;
fnx->last_data_change_time = ni->last_data_change_time; fnx->last_data_change_time = ni->last_data_change_time;
fnx->last_mft_change_time = ni->last_mft_change_time; fnx->last_mft_change_time = ni->last_mft_change_time;
fnx->last_access_time = ni->last_access_time; fnx->last_access_time = ni->last_access_time;
} else { }
else
{
fnx->creation_time = fn->creation_time; fnx->creation_time = fn->creation_time;
fnx->last_data_change_time = fn->last_data_change_time; fnx->last_data_change_time = fn->last_data_change_time;
fnx->last_mft_change_time = fn->last_mft_change_time; fnx->last_mft_change_time = fn->last_mft_change_time;
@ -863,14 +928,16 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
err = errno; err = errno;
} }
/* Check for real error occurred. */ /* Check for real error occurred. */
if (errno != ENOENT) { if ( errno != ENOENT )
{
err = errno; err = errno;
ntfs_log_perror( "Attribute lookup failed, inode %lld", ntfs_log_perror( "Attribute lookup failed, inode %lld",
( long long )ni->mft_no ); ( long long )ni->mft_no );
goto err_out; goto err_out;
} }
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
if (err) { if ( err )
{
errno = err; errno = err;
return -1; return -1;
} }
@ -905,7 +972,8 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
{ {
int ret = 0; int ret = 0;
int err = 0; int err = 0;
if (!ni) { if ( !ni )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_error( "Failed to sync NULL inode\n" ); ntfs_log_error( "Failed to sync NULL inode\n" );
return -1; return -1;
@ -915,8 +983,10 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
/* Update STANDARD_INFORMATION. */ /* Update STANDARD_INFORMATION. */
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 && if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
ntfs_inode_sync_standard_information(ni)) { ntfs_inode_sync_standard_information( ni ) )
if (!err || errno == EIO) { {
if ( !err || errno == EIO )
{
err = errno; err = errno;
if ( err != EIO ) if ( err != EIO )
err = EBUSY; err = EBUSY;
@ -926,8 +996,10 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
/* Update FILE_NAME's in the index. */ /* Update FILE_NAME's in the index. */
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 && if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
NInoFileNameTestAndClearDirty( ni ) && NInoFileNameTestAndClearDirty( ni ) &&
ntfs_inode_sync_file_name(ni, dir_ni)) { ntfs_inode_sync_file_name( ni, dir_ni ) )
if (!err || errno == EIO) { {
if ( !err || errno == EIO )
{
err = errno; err = errno;
if ( err != EIO ) if ( err != EIO )
err = EBUSY; err = EBUSY;
@ -939,12 +1011,15 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
/* Write out attribute list from cache to disk. */ /* Write out attribute list from cache to disk. */
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 && if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) { NInoAttrList( ni ) && NInoAttrListTestAndClearDirty( ni ) )
{
ntfs_attr *na; ntfs_attr *na;
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 ); na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
if (!na) { if ( !na )
if (!err || errno == EIO) { {
if ( !err || errno == EIO )
{
err = errno; err = errno;
if ( err != EIO ) if ( err != EIO )
err = EBUSY; err = EBUSY;
@ -956,10 +1031,13 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
goto sync_inode; goto sync_inode;
} }
if (na->data_size == ni->attr_list_size) { if ( na->data_size == ni->attr_list_size )
{
if ( ntfs_attr_pwrite( na, 0, ni->attr_list_size, if ( ntfs_attr_pwrite( na, 0, ni->attr_list_size,
ni->attr_list) != ni->attr_list_size) { ni->attr_list ) != ni->attr_list_size )
if (!err || errno == EIO) { {
if ( !err || errno == EIO )
{
err = errno; err = errno;
if ( err != EIO ) if ( err != EIO )
err = EBUSY; err = EBUSY;
@ -969,7 +1047,9 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
} }
NInoAttrListSetDirty( ni ); NInoAttrListSetDirty( ni );
} }
} else { }
else
{
err = EIO; err = EIO;
ntfs_log_error( "Attribute list sync failed (bad size, " ntfs_log_error( "Attribute list sync failed (bad size, "
"inode %lld)\n", ( long long )ni->mft_no ); "inode %lld)\n", ( long long )ni->mft_no );
@ -980,9 +1060,12 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
sync_inode: sync_inode:
/* Write this inode out to the $MFT (and $MFTMirr if applicable). */ /* Write this inode out to the $MFT (and $MFTMirr if applicable). */
if (NInoTestAndClearDirty(ni)) { if ( NInoTestAndClearDirty( ni ) )
if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) { {
if (!err || errno == EIO) { if ( ntfs_mft_record_write( ni->vol, ni->mft_no, ni->mrec ) )
{
if ( !err || errno == EIO )
{
err = errno; err = errno;
if ( err != EIO ) if ( err != EIO )
err = EBUSY; err = EBUSY;
@ -994,10 +1077,12 @@ sync_inode:
} }
/* If this is a base inode with extents write all dirty extents, too. */ /* If this is a base inode with extents write all dirty extents, too. */
if (ni->nr_extents > 0) { if ( ni->nr_extents > 0 )
{
s32 i; s32 i;
for (i = 0; i < ni->nr_extents; ++i) { for ( i = 0; i < ni->nr_extents; ++i )
{
ntfs_inode *eni; ntfs_inode *eni;
eni = ni->extent_nis[i]; eni = ni->extent_nis[i];
@ -1005,8 +1090,10 @@ sync_inode:
continue; continue;
if ( ntfs_mft_record_write( eni->vol, eni->mft_no, if ( ntfs_mft_record_write( eni->vol, eni->mft_no,
eni->mrec)) { eni->mrec ) )
if (!err || errno == EIO) { {
if ( !err || errno == EIO )
{
err = errno; err = errno;
if ( err != EIO ) if ( err != EIO )
err = EBUSY; err = EBUSY;
@ -1020,7 +1107,8 @@ sync_inode:
} }
} }
if (err) { if ( err )
{
errno = err; errno = err;
ret = -1; ret = -1;
} }
@ -1043,10 +1131,12 @@ int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
int res; int res;
res = ntfs_inode_sync_in_dir( ni, dir_ni ); res = ntfs_inode_sync_in_dir( ni, dir_ni );
if (res) { if ( res )
{
if ( errno != EIO ) if ( errno != EIO )
errno = EBUSY; errno = EBUSY;
} else }
else
res = ntfs_inode_close( ni ); res = ntfs_inode_close( ni );
return ( res ); return ( res );
} }
@ -1071,7 +1161,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
ATTR_LIST_ENTRY *ale = NULL; ATTR_LIST_ENTRY *ale = NULL;
ntfs_attr *na; ntfs_attr *na;
if (!ni) { if ( !ni )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s", __FUNCTION__ ); ntfs_log_perror( "%s", __FUNCTION__ );
return -1; return -1;
@ -1079,7 +1170,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
ntfs_log_trace( "inode %llu\n", ( unsigned long long ) ni->mft_no ); ntfs_log_trace( "inode %llu\n", ( unsigned long long ) ni->mft_no );
if (NInoAttrList(ni) || ni->nr_extents) { if ( NInoAttrList( ni ) || ni->nr_extents )
{
errno = EEXIST; errno = EEXIST;
ntfs_log_perror( "Inode already has attribute list" ); ntfs_log_perror( "Inode already has attribute list" );
return -1; return -1;
@ -1087,16 +1179,19 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
/* Form attribute list. */ /* Form attribute list. */
ctx = ntfs_attr_get_search_ctx( ni, NULL ); ctx = ntfs_attr_get_search_ctx( ni, NULL );
if (!ctx) { if ( !ctx )
{
err = errno; err = errno;
goto err_out; goto err_out;
} }
/* Walk through all attributes. */ /* Walk through all attributes. */
while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { while ( !ntfs_attr_lookup( AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx ) )
{
int ale_size; int ale_size;
if (ctx->attr->type == AT_ATTRIBUTE_LIST) { if ( ctx->attr->type == AT_ATTRIBUTE_LIST )
{
err = EIO; err = EIO;
ntfs_log_perror( "Attribute list already present" ); ntfs_log_perror( "Attribute list already present" );
goto put_err_out; goto put_err_out;
@ -1107,7 +1202,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
al_len += ale_size; al_len += ale_size;
aln = realloc( al, al_len ); aln = realloc( al, al_len );
if (!aln) { if ( !aln )
{
err = errno; err = errno;
ntfs_log_perror( "Failed to realloc %d bytes", al_len ); ntfs_log_perror( "Failed to realloc %d bytes", al_len );
goto put_err_out; goto put_err_out;
@ -1136,7 +1232,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
ale = ( ATTR_LIST_ENTRY * )( al + al_len ); ale = ( ATTR_LIST_ENTRY * )( al + al_len );
} }
/* Check for real error occurred. */ /* Check for real error occurred. */
if (errno != ENOENT) { if ( errno != ENOENT )
{
err = errno; err = errno;
ntfs_log_perror( "%s: Attribute lookup failed, inode %lld", ntfs_log_perror( "%s: Attribute lookup failed, inode %lld",
__FUNCTION__, ( long long )ni->mft_no ); __FUNCTION__, ( long long )ni->mft_no );
@ -1152,9 +1249,11 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
/* Free space if there is not enough it for $ATTRIBUTE_LIST. */ /* Free space if there is not enough it for $ATTRIBUTE_LIST. */
if ( le32_to_cpu( ni->mrec->bytes_allocated ) - if ( le32_to_cpu( ni->mrec->bytes_allocated ) -
le32_to_cpu( ni->mrec->bytes_in_use ) < le32_to_cpu( ni->mrec->bytes_in_use ) <
offsetof(ATTR_RECORD, resident_end)) { offsetof( ATTR_RECORD, resident_end ) )
{
if ( ntfs_inode_free_space( ni, if ( ntfs_inode_free_space( ni,
offsetof(ATTR_RECORD, resident_end))) { offsetof( ATTR_RECORD, resident_end ) ) )
{
/* Failed to free space. */ /* Failed to free space. */
err = errno; err = errno;
ntfs_log_perror( "Failed to free space for attrlist" ); ntfs_log_perror( "Failed to free space for attrlist" );
@ -1164,7 +1263,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
/* Add $ATTRIBUTE_LIST to mft record. */ /* Add $ATTRIBUTE_LIST to mft record. */
if ( ntfs_resident_attr_record_add( ni, if ( ntfs_resident_attr_record_add( ni,
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) { AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0 ) < 0 )
{
err = errno; err = errno;
ntfs_log_perror( "Couldn't add $ATTRIBUTE_LIST to MFT" ); ntfs_log_perror( "Couldn't add $ATTRIBUTE_LIST to MFT" );
goto rollback; goto rollback;
@ -1172,12 +1272,14 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
/* Resize it. */ /* Resize it. */
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 ); na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
if (!na) { if ( !na )
{
err = errno; err = errno;
ntfs_log_perror( "Failed to open just added $ATTRIBUTE_LIST" ); ntfs_log_perror( "Failed to open just added $ATTRIBUTE_LIST" );
goto remove_attrlist_record; goto remove_attrlist_record;
} }
if (ntfs_attr_truncate(na, al_len)) { if ( ntfs_attr_truncate( na, al_len ) )
{
err = errno; err = errno;
ntfs_log_perror( "Failed to resize just added $ATTRIBUTE_LIST" ); ntfs_log_perror( "Failed to resize just added $ATTRIBUTE_LIST" );
ntfs_attr_close( na ); ntfs_attr_close( na );
@ -1195,10 +1297,12 @@ remove_attrlist_record:
/* Remove $ATTRIBUTE_LIST record. */ /* Remove $ATTRIBUTE_LIST record. */
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
if ( !ntfs_attr_lookup( AT_ATTRIBUTE_LIST, NULL, 0, if ( !ntfs_attr_lookup( AT_ATTRIBUTE_LIST, NULL, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) { CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
if ( ntfs_attr_record_rm( ctx ) ) if ( ntfs_attr_record_rm( ctx ) )
ntfs_log_perror( "Rollback failed to remove attrlist" ); ntfs_log_perror( "Rollback failed to remove attrlist" );
} else }
else
ntfs_log_perror( "Rollback failed to find attrlist" ); ntfs_log_perror( "Rollback failed to find attrlist" );
/* Setup back in-memory runlist. */ /* Setup back in-memory runlist. */
ni->attr_list = al; ni->attr_list = al;
@ -1211,17 +1315,21 @@ rollback:
*/ */
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
ale = ( ATTR_LIST_ENTRY* )al; ale = ( ATTR_LIST_ENTRY* )al;
while ((u8*)ale < al + al_len) { while ( ( u8* )ale < al + al_len )
if (MREF_LE(ale->mft_reference) != ni->mft_no) { {
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
{
if ( !ntfs_attr_lookup( ale->type, ale->name, if ( !ntfs_attr_lookup( ale->type, ale->name,
ale->name_length, ale->name_length,
CASE_SENSITIVE, CASE_SENSITIVE,
sle64_to_cpu( ale->lowest_vcn ), sle64_to_cpu( ale->lowest_vcn ),
NULL, 0, ctx)) { NULL, 0, ctx ) )
{
if ( ntfs_attr_record_move_to( ctx, ni ) ) if ( ntfs_attr_record_move_to( ctx, ni ) )
ntfs_log_perror( "Rollback failed to " ntfs_log_perror( "Rollback failed to "
"move attribute" ); "move attribute" );
} else }
else
ntfs_log_perror( "Rollback failed to find attr" ); ntfs_log_perror( "Rollback failed to find attr" );
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
} }
@ -1252,7 +1360,8 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size)
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
int freed; int freed;
if (!ni || size < 0) { if ( !ni || size < 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: ni=%p size=%d", __FUNCTION__, ni, size ); ntfs_log_perror( "%s: ni=%p size=%d", __FUNCTION__, ni, size );
return -1; return -1;
@ -1277,13 +1386,15 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size)
if ( ntfs_attr_position( AT_FILE_NAME, ctx ) ) if ( ntfs_attr_position( AT_FILE_NAME, ctx ) )
goto put_err_out; goto put_err_out;
while (1) { while ( 1 )
{
int record_size; int record_size;
/* /*
* Check whether attribute is from different MFT record. If so, * Check whether attribute is from different MFT record. If so,
* find next, because we don't need such. * find next, because we don't need such.
*/ */
while (ctx->ntfs_ino->mft_no != ni->mft_no) { while ( ctx->ntfs_ino->mft_no != ni->mft_no )
{
retry: retry:
if ( ntfs_attr_position( AT_UNUSED, ctx ) ) if ( ntfs_attr_position( AT_UNUSED, ctx ) )
goto put_err_out; goto put_err_out;
@ -1298,14 +1409,16 @@ retry:
record_size = le32_to_cpu( ctx->attr->length ); record_size = le32_to_cpu( ctx->attr->length );
if (ntfs_attr_record_move_away(ctx, 0)) { if ( ntfs_attr_record_move_away( ctx, 0 ) )
{
ntfs_log_perror( "Failed to move out attribute #2" ); ntfs_log_perror( "Failed to move out attribute #2" );
break; break;
} }
freed += record_size; freed += record_size;
/* Check whether we are done. */ /* Check whether we are done. */
if (size <= freed) { if ( size <= freed )
{
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
return 0; return 0;
} }
@ -1339,7 +1452,8 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
{ {
ntfs_time now; ntfs_time now;
if (!ni) { if ( !ni )
{
ntfs_log_error( "%s(): Invalid arguments.\n", __FUNCTION__ ); ntfs_log_error( "%s(): Invalid arguments.\n", __FUNCTION__ );
return; return;
} }
@ -1377,7 +1491,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
int len, ret = 0; int len, ret = 0;
ntfschar *ustr; ntfschar *ustr;
if (!attr) { if ( !attr )
{
ntfs_log_error( "Invalid argument.\n" ); ntfs_log_error( "Invalid argument.\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -1389,7 +1504,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
if ( attr->type != AT_DATA ) if ( attr->type != AT_DATA )
return 0; return 0;
if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) { if ( ( ustr = ntfs_str2ucs( "$Bad", &len ) ) == NULL )
{
ntfs_log_perror( "Couldn't convert '$Bad' to Unicode" ); ntfs_log_perror( "Couldn't convert '$Bad' to Unicode" );
return -1; return -1;
} }
@ -1425,32 +1541,40 @@ int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size)
ret = 0; ret = 0;
ctx = ntfs_attr_get_search_ctx( ni, NULL ); ctx = ntfs_attr_get_search_ctx( ni, NULL );
if (ctx) { if ( ctx )
{
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED, if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { 0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
{
ntfs_log_perror( "Failed to get standard info (inode %lld)", ntfs_log_perror( "Failed to get standard info (inode %lld)",
( long long )ni->mft_no ); ( long long )ni->mft_no );
} else { }
else
{
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr + std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
le16_to_cpu( ctx->attr->value_offset ) ); le16_to_cpu( ctx->attr->value_offset ) );
if (value && (size >= 8)) { if ( value && ( size >= 8 ) )
{
times = ( u64* )value; times = ( u64* )value;
times[0] = le64_to_cpu( std_info->creation_time ); times[0] = le64_to_cpu( std_info->creation_time );
ret = 8; ret = 8;
if (size >= 16) { if ( size >= 16 )
{
times[1] = le64_to_cpu( std_info->last_data_change_time ); times[1] = le64_to_cpu( std_info->last_data_change_time );
ret = 16; ret = 16;
} }
if (size >= 24) { if ( size >= 24 )
{
times[2] = le64_to_cpu( std_info->last_access_time ); times[2] = le64_to_cpu( std_info->last_access_time );
ret = 24; ret = 24;
} }
if (size >= 32) { if ( size >= 32 )
{
times[3] = le64_to_cpu( std_info->last_mft_change_time ); times[3] = le64_to_cpu( std_info->last_mft_change_time );
ret = 32; ret = 32;
} }
} else }
if (!size) else if ( !size )
ret = 32; ret = 32;
else else
ret = -ERANGE; ret = -ERANGE;
@ -1486,18 +1610,23 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
int ret; int ret;
ret = -1; ret = -1;
if ((size >= 8) && !(flags & XATTR_CREATE)) { if ( ( size >= 8 ) && !( flags & XATTR_CREATE ) )
{
times = ( const u64* )value; times = ( const u64* )value;
now = ntfs_current_time(); now = ntfs_current_time();
/* update the standard information attribute */ /* update the standard information attribute */
ctx = ntfs_attr_get_search_ctx( ni, NULL ); ctx = ntfs_attr_get_search_ctx( ni, NULL );
if (ctx) { if ( ctx )
{
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION,
AT_UNNAMED, 0, CASE_SENSITIVE, AT_UNNAMED, 0, CASE_SENSITIVE,
0, NULL, 0, ctx)) { 0, NULL, 0, ctx ) )
{
ntfs_log_perror( "Failed to get standard info (inode %lld)", ntfs_log_perror( "Failed to get standard info (inode %lld)",
( long long )ni->mft_no ); ( long long )ni->mft_no );
} else { }
else
{
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr + std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
le16_to_cpu( ctx->attr->value_offset ) ); le16_to_cpu( ctx->attr->value_offset ) );
/* /*
@ -1512,12 +1641,14 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
std_info->creation_time = cpu_to_le64( times[0] ); std_info->creation_time = cpu_to_le64( times[0] );
ni->creation_time ni->creation_time
= std_info->creation_time; = std_info->creation_time;
if (size >= 16) { if ( size >= 16 )
{
std_info->last_data_change_time = cpu_to_le64( times[1] ); std_info->last_data_change_time = cpu_to_le64( times[1] );
ni->last_data_change_time ni->last_data_change_time
= std_info->last_data_change_time; = std_info->last_data_change_time;
} }
if (size >= 24) { if ( size >= 24 )
{
std_info->last_access_time = cpu_to_le64( times[2] ); std_info->last_access_time = cpu_to_le64( times[2] );
ni->last_access_time ni->last_access_time
= std_info->last_access_time; = std_info->last_access_time;
@ -1532,7 +1663,8 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
cnt = 0; cnt = 0;
while ( !ntfs_attr_lookup( AT_FILE_NAME, while ( !ntfs_attr_lookup( AT_FILE_NAME,
AT_UNNAMED, 0, CASE_SENSITIVE, AT_UNNAMED, 0, CASE_SENSITIVE,
0, NULL, 0, ctx)) { 0, NULL, 0, ctx ) )
{
fn = ( FILE_NAME_ATTR* )( ( u8 * )ctx->attr + fn = ( FILE_NAME_ATTR* )( ( u8 * )ctx->attr +
le16_to_cpu( ctx->attr->value_offset ) ); le16_to_cpu( ctx->attr->value_offset ) );
fn->creation_time fn->creation_time
@ -1548,15 +1680,16 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
} }
if ( cnt ) if ( cnt )
ret = 0; ret = 0;
else { else
{
ntfs_log_perror( "Failed to get file names (inode %lld)", ntfs_log_perror( "Failed to get file names (inode %lld)",
( long long )ni->mft_no ); ( long long )ni->mft_no );
} }
} }
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
} }
} else }
if (size < 8) else if ( size < 8 )
errno = ERANGE; errno = ERANGE;
else else
errno = EEXIST; errno = EEXIST;

View File

@ -40,7 +40,8 @@ typedef struct _ntfs_inode ntfs_inode;
* Defined bits for the state field in the ntfs_inode structure. * Defined bits for the state field in the ntfs_inode structure.
* (f) = files only, (d) = directories only * (f) = files only, (d) = directories only
*/ */
typedef enum { typedef enum
{
NI_Dirty, /* 1: Mft record needs to be written to disk. */ NI_Dirty, /* 1: Mft record needs to be written to disk. */
/* The NI_AttrList* tests only make sense for base inodes. */ /* The NI_AttrList* tests only make sense for base inodes. */
@ -103,7 +104,8 @@ typedef enum {
* It is just used as an extension to the fields already provided in the VFS * It is just used as an extension to the fields already provided in the VFS
* inode. * inode.
*/ */
struct _ntfs_inode { struct _ntfs_inode
{
u64 mft_no; /* Inode / mft record number. */ u64 mft_no; /* Inode / mft record number. */
MFT_RECORD *mrec; /* The actual mft record of the inode. */ MFT_RECORD *mrec; /* The actual mft record of the inode. */
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */ ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
@ -122,7 +124,8 @@ struct _ntfs_inode {
s32 nr_extents; /* For a base mft record, the number of s32 nr_extents; /* For a base mft record, the number of
attached extent inodes (0 if none), for attached extent inodes (0 if none), for
extent records this is -1. */ extent records this is -1. */
union { /* This union is only used if nr_extents != 0. */ union /* This union is only used if nr_extents != 0. */
{
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
ntfs inodes of the extent mft ntfs inodes of the extent mft
records belonging to this base records belonging to this base
@ -166,7 +169,8 @@ struct _ntfs_inode {
le64 usn; le64 usn;
}; };
typedef enum { typedef enum
{
NTFS_UPDATE_ATIME = 1 << 0, NTFS_UPDATE_ATIME = 1 << 0,
NTFS_UPDATE_MTIME = 1 << 1, NTFS_UPDATE_MTIME = 1 << 1,
NTFS_UPDATE_CTIME = 1 << 2, NTFS_UPDATE_CTIME = 1 << 2,

View File

@ -46,7 +46,8 @@
/** /**
* struct BIOS_PARAMETER_BLOCK - BIOS parameter block (bpb) structure. * struct BIOS_PARAMETER_BLOCK - BIOS parameter block (bpb) structure.
*/ */
typedef struct { typedef struct
{
u16 bytes_per_sector; /* Size of a sector in bytes. */ u16 bytes_per_sector; /* Size of a sector in bytes. */
u8 sectors_per_cluster; /* Size of a cluster in sectors. */ u8 sectors_per_cluster; /* Size of a cluster in sectors. */
u16 reserved_sectors; /* zero */ u16 reserved_sectors; /* zero */
@ -67,7 +68,8 @@ typedef struct {
/** /**
* struct NTFS_BOOT_SECTOR - NTFS boot sector structure. * struct NTFS_BOOT_SECTOR - NTFS boot sector structure.
*/ */
typedef struct { typedef struct
{
u8 jump[3]; /* Irrelevant (jump to boot up code).*/ u8 jump[3]; /* Irrelevant (jump to boot up code).*/
u64 oem_id; /* Magic "NTFS ". */ u64 oem_id; /* Magic "NTFS ". */
/*0x0b*/BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */ /*0x0b*/BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */
@ -100,7 +102,8 @@ typedef struct {
* Magic identifiers present at the beginning of all ntfs record containing * Magic identifiers present at the beginning of all ntfs record containing
* records (like mft records for example). * records (like mft records for example).
*/ */
typedef enum { typedef enum
{
/* Found in $MFT/$DATA. */ /* Found in $MFT/$DATA. */
magic_FILE = const_cpu_to_le32( 0x454c4946 ), /* Mft entry. */ magic_FILE = const_cpu_to_le32( 0x454c4946 ), /* Mft entry. */
magic_INDX = const_cpu_to_le32( 0x58444e49 ), /* Index buffer. */ magic_INDX = const_cpu_to_le32( 0x58444e49 ), /* Index buffer. */
@ -182,7 +185,8 @@ typedef enum {
* This formula can be used as a consistency check in that usa_ofs + * This formula can be used as a consistency check in that usa_ofs +
* (usa_count * 2) has to be less than or equal to 510. * (usa_count * 2) has to be less than or equal to 510.
*/ */
typedef struct { typedef struct
{
NTFS_RECORD_TYPES magic;/* A four-byte magic identifying the NTFS_RECORD_TYPES magic;/* A four-byte magic identifying the
record type and/or status. */ record type and/or status. */
u16 usa_ofs; /* Offset to the Update Sequence Array (usa) u16 usa_ofs; /* Offset to the Update Sequence Array (usa)
@ -201,7 +205,8 @@ typedef struct {
* mft records. Also, the sequence number for each of the system files is * mft records. Also, the sequence number for each of the system files is
* always equal to their mft record number and it is never modified. * always equal to their mft record number and it is never modified.
*/ */
typedef enum { typedef enum
{
FILE_MFT = 0, /* Master file table (mft). Data attribute FILE_MFT = 0, /* Master file table (mft). Data attribute
contains the entries and bitmap attribute contains the entries and bitmap attribute
records which ones are in use (bit==1). */ records which ones are in use (bit==1). */
@ -254,7 +259,8 @@ typedef enum {
* index, that means an INDEX_ROOT and an INDEX_ALLOCATION with a name other * index, that means an INDEX_ROOT and an INDEX_ALLOCATION with a name other
* than "$I30". It is unknown if it is limited to metadata files only. * than "$I30". It is unknown if it is limited to metadata files only.
*/ */
typedef enum { typedef enum
{
MFT_RECORD_IN_USE = const_cpu_to_le16( 0x0001 ), MFT_RECORD_IN_USE = const_cpu_to_le16( 0x0001 ),
MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16( 0x0002 ), MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16( 0x0002 ),
MFT_RECORD_IS_4 = const_cpu_to_le16( 0x0004 ), MFT_RECORD_IS_4 = const_cpu_to_le16( 0x0004 ),
@ -335,7 +341,8 @@ typedef u64 MFT_REF;
* in that it only consists of the attribute type code AT_END and none of the * in that it only consists of the attribute type code AT_END and none of the
* other members of the attribute structure are present. * other members of the attribute structure are present.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*Ofs*/
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */ NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
@ -409,7 +416,8 @@ typedef struct {
* *
* This is the version without the NTFS 3.1+ specific fields. * This is the version without the NTFS 3.1+ specific fields.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*Ofs*/
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */ NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
@ -486,7 +494,8 @@ typedef struct {
* enum exchanging AT_ for the dollar sign ($). If that isn't a revealing * enum exchanging AT_ for the dollar sign ($). If that isn't a revealing
* choice of symbol... (-; * choice of symbol... (-;
*/ */
typedef enum { typedef enum
{
AT_UNUSED = const_cpu_to_le32( 0 ), AT_UNUSED = const_cpu_to_le32( 0 ),
AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10 ), AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10 ),
AT_ATTRIBUTE_LIST = const_cpu_to_le32( 0x20 ), AT_ATTRIBUTE_LIST = const_cpu_to_le32( 0x20 ),
@ -545,7 +554,8 @@ typedef enum {
* the 2nd object_id. If the first u32 values of both object_ids were * the 2nd object_id. If the first u32 values of both object_ids were
* equal then the second u32 values would be compared, etc. * equal then the second u32 values would be compared, etc.
*/ */
typedef enum { typedef enum
{
COLLATION_BINARY = const_cpu_to_le32( 0 ), /* Collate by binary COLLATION_BINARY = const_cpu_to_le32( 0 ), /* Collate by binary
compare where the first byte is most compare where the first byte is most
significant. */ significant. */
@ -573,7 +583,8 @@ typedef enum {
* name attribute has this flag set and this is the only attribute indexed in * name attribute has this flag set and this is the only attribute indexed in
* NT4. * NT4.
*/ */
typedef enum { typedef enum
{
ATTR_DEF_INDEXABLE = const_cpu_to_le32( 0x02 ), /* Attribute can be ATTR_DEF_INDEXABLE = const_cpu_to_le32( 0x02 ), /* Attribute can be
indexed. */ indexed. */
ATTR_DEF_MULTIPLE = const_cpu_to_le32( 0x04 ), /* Attribute type ATTR_DEF_MULTIPLE = const_cpu_to_le32( 0x04 ), /* Attribute type
@ -611,9 +622,11 @@ typedef enum {
* attribute can be resident/non-resident and possibly other things, but the * attribute can be resident/non-resident and possibly other things, but the
* actual bits are unknown. * actual bits are unknown.
*/ */
typedef struct { typedef struct
{
/*hex ofs*/ /*hex ofs*/
/* 0*/ ntfschar name[0x40]; /* Unicode name of the attribute. Zero /* 0*/
ntfschar name[0x40]; /* Unicode name of the attribute. Zero
terminated. */ terminated. */
/* 80*/ ATTR_TYPES type; /* Type of the attribute. */ /* 80*/ ATTR_TYPES type; /* Type of the attribute. */
/* 84*/ u32 display_rule; /* Default display rule. /* 84*/ u32 display_rule; /* Default display rule.
@ -628,7 +641,8 @@ typedef struct {
/** /**
* enum ATTR_FLAGS - Attribute flags (16-bit). * enum ATTR_FLAGS - Attribute flags (16-bit).
*/ */
typedef enum { typedef enum
{
ATTR_IS_COMPRESSED = const_cpu_to_le16( 0x0001 ), ATTR_IS_COMPRESSED = const_cpu_to_le16( 0x0001 ),
ATTR_COMPRESSION_MASK = const_cpu_to_le16( 0x00ff ), /* Compression ATTR_COMPRESSION_MASK = const_cpu_to_le16( 0x00ff ), /* Compression
method mask. Also, first method mask. Also, first
@ -707,7 +721,8 @@ typedef enum {
/** /**
* enum RESIDENT_ATTR_FLAGS - Flags of resident attributes (8-bit). * enum RESIDENT_ATTR_FLAGS - Flags of resident attributes (8-bit).
*/ */
typedef enum { typedef enum
{
RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index
(has implications for deleting and (has implications for deleting and
modifying the attribute). */ modifying the attribute). */
@ -718,9 +733,11 @@ typedef enum {
* *
* Always aligned to 8-byte boundary. * Always aligned to 8-byte boundary.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*Ofs*/
/* 0*/ ATTR_TYPES type; /* The (32-bit) type of the attribute. */ /* 0*/
ATTR_TYPES type; /* The (32-bit) type of the attribute. */
/* 4*/ u32 length; /* Byte size of the resident part of the /* 4*/ u32 length; /* Byte size of the resident part of the
attribute (aligned to 8-byte boundary). attribute (aligned to 8-byte boundary).
Used to get to the next attribute. */ Used to get to the next attribute. */
@ -742,10 +759,13 @@ typedef struct {
number is unique within this mft record (see number is unique within this mft record (see
MFT_RECORD/next_attribute_instance notes MFT_RECORD/next_attribute_instance notes
above for more details). */ above for more details). */
/* 16*/ union { /* 16*/ union
{
/* Resident attributes. */ /* Resident attributes. */
struct { struct
/* 16 */ u32 value_length; /* Byte size of attribute value. */ {
/* 16 */
u32 value_length; /* Byte size of attribute value. */
/* 20 */ u16 value_offset; /* Byte offset of the attribute /* 20 */ u16 value_offset; /* Byte offset of the attribute
value from the start of the value from the start of the
attribute record. When creating, attribute record. When creating,
@ -761,8 +781,10 @@ typedef struct {
a resident attribute. */ a resident attribute. */
} __attribute__( ( __packed__ ) ); } __attribute__( ( __packed__ ) );
/* Non-resident attributes. */ /* Non-resident attributes. */
struct { struct
/* 16*/ VCN lowest_vcn; /* Lowest valid virtual cluster number {
/* 16*/
VCN lowest_vcn; /* Lowest valid virtual cluster number
for this portion of the attribute value or for this portion of the attribute value or
0 if this is the only extent (usually the 0 if this is the only extent (usually the
case). - Only when an attribute list is used case). - Only when an attribute list is used
@ -825,7 +847,8 @@ typedef ATTR_RECORD ATTR_REC;
/** /**
* enum FILE_ATTR_FLAGS - File attribute flags (32-bit). * enum FILE_ATTR_FLAGS - File attribute flags (32-bit).
*/ */
typedef enum { typedef enum
{
/* /*
* These flags are only present in the STANDARD_INFORMATION attribute * These flags are only present in the STANDARD_INFORMATION attribute
* (in the field file_attributes). * (in the field file_attributes).
@ -905,9 +928,11 @@ typedef enum {
* correct by practical experimentation on Windows NT4 SP6a and is hence * correct by practical experimentation on Windows NT4 SP6a and is hence
* assumed to be the one and only correct interpretation. * assumed to be the one and only correct interpretation.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*Ofs*/
/* 0*/ s64 creation_time; /* Time file was created. Updated when /* 0*/
s64 creation_time; /* Time file was created. Updated when
a filename is changed(?). */ a filename is changed(?). */
/* 8*/ s64 last_data_change_time; /* Time the data attribute was last /* 8*/ s64 last_data_change_time; /* Time the data attribute was last
modified. */ modified. */
@ -922,16 +947,20 @@ typedef struct {
last access times updates can be last access times updates can be
disabled altogether for speed. */ disabled altogether for speed. */
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ /* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 36*/ union { /* 36*/ union
{
/* NTFS 1.2 (and previous, presumably) */ /* NTFS 1.2 (and previous, presumably) */
struct { struct
/* 36 */ u8 reserved12[12]; /* Reserved/alignment to 8-byte {
/* 36 */
u8 reserved12[12]; /* Reserved/alignment to 8-byte
boundary. */ boundary. */
/* 48 */ void *v1_end[0]; /* Marker for offsetof(). */ /* 48 */ void *v1_end[0]; /* Marker for offsetof(). */
} __attribute__( ( __packed__ ) ); } __attribute__( ( __packed__ ) );
/* sizeof() = 48 bytes */ /* sizeof() = 48 bytes */
/* NTFS 3.0 */ /* NTFS 3.0 */
struct { struct
{
/* /*
* If a volume has been upgraded from a previous NTFS version, then these * If a volume has been upgraded from a previous NTFS version, then these
* fields are present only if the file has been accessed since the upgrade. * fields are present only if the file has been accessed since the upgrade.
@ -951,7 +980,8 @@ typedef struct {
* views that as a corruption, assuming that it behaves like this for all * views that as a corruption, assuming that it behaves like this for all
* attributes. * attributes.
*/ */
/* 36*/ u32 maximum_versions; /* Maximum allowed versions for /* 36*/
u32 maximum_versions; /* Maximum allowed versions for
file. Zero if version numbering is disabled. */ file. Zero if version numbering is disabled. */
/* 40*/ u32 version_number; /* This file's version (if any). /* 40*/ u32 version_number; /* This file's version (if any).
Set to zero if maximum_versions is zero. */ Set to zero if maximum_versions is zero. */
@ -1016,9 +1046,11 @@ typedef struct {
* NTFS 3.0 volumes). * NTFS 3.0 volumes).
* - There are many named streams. * - There are many named streams.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*Ofs*/
/* 0*/ ATTR_TYPES type; /* Type of referenced attribute. */ /* 0*/
ATTR_TYPES type; /* Type of referenced attribute. */
/* 4*/ u16 length; /* Byte size of this entry. */ /* 4*/ u16 length; /* Byte size of this entry. */
/* 6*/ u8 name_length; /* Size in Unicode chars of the name of the /* 6*/ u8 name_length; /* Size in Unicode chars of the name of the
attribute or 0 if unnamed. */ attribute or 0 if unnamed. */
@ -1057,7 +1089,8 @@ typedef struct {
* enum FILE_NAME_TYPE_FLAGS - Possible namespaces for filenames in ntfs. * enum FILE_NAME_TYPE_FLAGS - Possible namespaces for filenames in ntfs.
* (8-bit). * (8-bit).
*/ */
typedef enum { typedef enum
{
FILE_NAME_POSIX = 0x00, FILE_NAME_POSIX = 0x00,
/* This is the largest namespace. It is case sensitive and /* This is the largest namespace. It is case sensitive and
allows all Unicode characters except for: '\0' and '/'. allows all Unicode characters except for: '\0' and '/'.
@ -1093,9 +1126,11 @@ typedef enum {
* correct by practical experimentation on Windows NT4 SP6a and is hence * correct by practical experimentation on Windows NT4 SP6a and is hence
* assumed to be the one and only correct interpretation. * assumed to be the one and only correct interpretation.
*/ */
typedef struct { typedef struct
{
/*hex ofs*/ /*hex ofs*/
/* 0*/ MFT_REF parent_directory; /* Directory this filename is /* 0*/
MFT_REF parent_directory; /* Directory this filename is
referenced from. */ referenced from. */
/* 8*/ s64 creation_time; /* Time file was created. */ /* 8*/ s64 creation_time; /* Time file was created. */
/* 10*/ s64 last_data_change_time; /* Time the data attribute was last /* 10*/ s64 last_data_change_time; /* Time the data attribute was last
@ -1116,9 +1151,13 @@ typedef struct {
/* 30*/ s64 data_size; /* Byte size of actual data in data /* 30*/ s64 data_size; /* Byte size of actual data in data
attribute. */ attribute. */
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ /* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 3c*/ union { /* 3c*/ union
/* 3c*/ struct { {
/* 3c*/ u16 packed_ea_size; /* Size of the buffer needed to /* 3c*/
struct
{
/* 3c*/
u16 packed_ea_size; /* Size of the buffer needed to
pack the extended attributes pack the extended attributes
(EAs), if such are present.*/ (EAs), if such are present.*/
/* 3e*/ u16 reserved; /* Reserved for alignment. */ /* 3e*/ u16 reserved; /* Reserved for alignment. */
@ -1146,7 +1185,8 @@ typedef struct {
* Example of a GUID: * Example of a GUID:
* 1F010768-5A73-BC91-0010-A52216A7227B * 1F010768-5A73-BC91-0010-A52216A7227B
*/ */
typedef struct { typedef struct
{
u32 data1; /* The first eight hexadecimal digits of the GUID. */ u32 data1; /* The first eight hexadecimal digits of the GUID. */
u16 data2; /* The first group of four hexadecimal digits. */ u16 data2; /* The first group of four hexadecimal digits. */
u16 data3; /* The second group of four hexadecimal digits. */ u16 data3; /* The second group of four hexadecimal digits. */
@ -1168,11 +1208,14 @@ typedef struct {
* equals the object_id. Optional (i.e. can be zero). * equals the object_id. Optional (i.e. can be zero).
* domain_id - Reserved (always zero). * domain_id - Reserved (always zero).
*/ */
typedef struct { typedef struct
{
MFT_REF mft_reference; /* Mft record containing the object_id in MFT_REF mft_reference; /* Mft record containing the object_id in
the index entry key. */ the index entry key. */
union { union
struct { {
struct
{
GUID birth_volume_id; GUID birth_volume_id;
GUID birth_object_id; GUID birth_object_id;
GUID domain_id; GUID domain_id;
@ -1186,7 +1229,8 @@ typedef struct {
* *
* NOTE: Always resident. * NOTE: Always resident.
*/ */
typedef struct { typedef struct
{
GUID object_id; /* Unique id assigned to the GUID object_id; /* Unique id assigned to the
file.*/ file.*/
/* The following fields are optional. The attribute value size is 16 /* The following fields are optional. The attribute value size is 16
@ -1196,8 +1240,10 @@ typedef struct {
when the fields are missing here, it is well possible that they are when the fields are missing here, it is well possible that they are
to be found within the $Extend/$ObjId system file indexed under the to be found within the $Extend/$ObjId system file indexed under the
above object_id. */ above object_id. */
union { union
struct { {
struct
{
GUID birth_volume_id; /* Unique id of volume on which GUID birth_volume_id; /* Unique id of volume on which
the file was first created.*/ the file was first created.*/
GUID birth_object_id; /* Unique id of file when it was GUID birth_object_id; /* Unique id of file when it was
@ -1215,7 +1261,8 @@ typedef struct {
* The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in * The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
* the SID structure (see below). * the SID structure (see below).
*/ */
typedef enum { /* SID string prefix. */ typedef enum /* SID string prefix. */
{
SECURITY_NULL_SID_AUTHORITY = {0, 0, 0, 0, 0, 0}, /* S-1-0 */ SECURITY_NULL_SID_AUTHORITY = {0, 0, 0, 0, 0, 0}, /* S-1-0 */
SECURITY_WORLD_SID_AUTHORITY = {0, 0, 0, 0, 0, 1}, /* S-1-1 */ SECURITY_WORLD_SID_AUTHORITY = {0, 0, 0, 0, 0, 1}, /* S-1-1 */
SECURITY_LOCAL_SID_AUTHORITY = {0, 0, 0, 0, 0, 2}, /* S-1-2 */ SECURITY_LOCAL_SID_AUTHORITY = {0, 0, 0, 0, 0, 2}, /* S-1-2 */
@ -1237,7 +1284,8 @@ typedef enum { /* SID string prefix. */
* made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and * made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and
* the relative identifier SECURITY_CREATOR_OWNER_RID (0). * the relative identifier SECURITY_CREATOR_OWNER_RID (0).
*/ */
typedef enum { /* Identifier authority. */ typedef enum /* Identifier authority. */
{
SECURITY_NULL_RID = 0, /* S-1-0 */ SECURITY_NULL_RID = 0, /* S-1-0 */
SECURITY_WORLD_RID = 0, /* S-1-1 */ SECURITY_WORLD_RID = 0, /* S-1-1 */
SECURITY_LOCAL_RID = 0, /* S-1-2 */ SECURITY_LOCAL_RID = 0, /* S-1-2 */
@ -1349,8 +1397,10 @@ typedef enum { /* Identifier authority. */
* *
* NOTE: This is stored as a big endian number. * NOTE: This is stored as a big endian number.
*/ */
typedef union { typedef union
struct { {
struct
{
u16 high_part; /* High 16-bits. */ u16 high_part; /* High 16-bits. */
u32 low_part; /* Low 32-bits. */ u32 low_part; /* Low 32-bits. */
} __attribute__( ( __packed__ ) ); } __attribute__( ( __packed__ ) );
@ -1385,7 +1435,8 @@ typedef union {
* sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID * sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID
* sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS * sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS
*/ */
typedef struct { typedef struct
{
u8 revision; u8 revision;
u8 sub_authority_count; u8 sub_authority_count;
SID_IDENTIFIER_AUTHORITY identifier_authority; SID_IDENTIFIER_AUTHORITY identifier_authority;
@ -1395,7 +1446,8 @@ typedef struct {
/** /**
* enum SID_CONSTANTS - Current constants for SIDs. * enum SID_CONSTANTS - Current constants for SIDs.
*/ */
typedef enum { typedef enum
{
SID_REVISION = 1, /* Current revision level. */ SID_REVISION = 1, /* Current revision level. */
SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */ SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */
SID_RECOMMENDED_SUB_AUTHORITIES = 1, /* Will change to around 6 in SID_RECOMMENDED_SUB_AUTHORITIES = 1, /* Will change to around 6 in
@ -1405,7 +1457,8 @@ typedef enum {
/** /**
* enum ACE_TYPES - The predefined ACE types (8-bit, see below). * enum ACE_TYPES - The predefined ACE types (8-bit, see below).
*/ */
typedef enum { typedef enum
{
ACCESS_MIN_MS_ACE_TYPE = 0, ACCESS_MIN_MS_ACE_TYPE = 0,
ACCESS_ALLOWED_ACE_TYPE = 0, ACCESS_ALLOWED_ACE_TYPE = 0,
ACCESS_DENIED_ACE_TYPE = 1, ACCESS_DENIED_ACE_TYPE = 1,
@ -1440,7 +1493,8 @@ typedef enum {
* FAILED_ACCESS_ACE_FLAG is only used with system audit and alarm ACE types * FAILED_ACCESS_ACE_FLAG is only used with system audit and alarm ACE types
* to indicate that a message is generated (in Windows!) for failed accesses. * to indicate that a message is generated (in Windows!) for failed accesses.
*/ */
typedef enum { typedef enum
{
/* The inheritance flags. */ /* The inheritance flags. */
OBJECT_INHERIT_ACE = 0x01, OBJECT_INHERIT_ACE = 0x01,
CONTAINER_INHERIT_ACE = 0x02, CONTAINER_INHERIT_ACE = 0x02,
@ -1467,7 +1521,8 @@ typedef enum {
* which specifies the type and size of the ACE. The format of the subsequent * which specifies the type and size of the ACE. The format of the subsequent
* data depends on the ACE type. * data depends on the ACE type.
*/ */
typedef struct { typedef struct
{
ACE_TYPES type; /* Type of the ACE. */ ACE_TYPES type; /* Type of the ACE. */
ACE_FLAGS flags; /* Flags describing the ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */
u16 size; /* Size in bytes of the ACE. */ u16 size; /* Size in bytes of the ACE. */
@ -1478,7 +1533,8 @@ typedef struct {
* *
* Defines the access rights. * Defines the access rights.
*/ */
typedef enum { typedef enum
{
/* /*
* The specific rights (bits 0 to 15). Depend on the type of the * The specific rights (bits 0 to 15). Depend on the type of the
* object being secured by the ACE. * object being secured by the ACE.
@ -1616,7 +1672,8 @@ typedef enum {
* *
* FIXME: What exactly is this and what is it for? (AIA) * FIXME: What exactly is this and what is it for? (AIA)
*/ */
typedef struct { typedef struct
{
ACCESS_MASK generic_read; ACCESS_MASK generic_read;
ACCESS_MASK generic_write; ACCESS_MASK generic_write;
ACCESS_MASK generic_execute; ACCESS_MASK generic_execute;
@ -1632,7 +1689,8 @@ typedef struct {
* *
* ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE * ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
*/ */
typedef struct { typedef struct
{
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */ /* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
ACE_TYPES type; /* Type of the ACE. */ ACE_TYPES type; /* Type of the ACE. */
ACE_FLAGS flags; /* Flags describing the ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */
@ -1646,7 +1704,8 @@ typedef struct {
/** /**
* enum OBJECT_ACE_FLAGS - The object ACE flags (32-bit). * enum OBJECT_ACE_FLAGS - The object ACE flags (32-bit).
*/ */
typedef enum { typedef enum
{
ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 1 ), ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 1 ),
ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 2 ), ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 2 ),
} OBJECT_ACE_FLAGS; } OBJECT_ACE_FLAGS;
@ -1654,7 +1713,8 @@ typedef enum {
/** /**
* struct ACCESS_ALLOWED_OBJECT_ACE - * struct ACCESS_ALLOWED_OBJECT_ACE -
*/ */
typedef struct { typedef struct
{
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */ /* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
ACE_TYPES type; /* Type of the ACE. */ ACE_TYPES type; /* Type of the ACE. */
ACE_FLAGS flags; /* Flags describing the ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */
@ -1678,7 +1738,8 @@ typedef struct {
* zero or more access control entries (ACEs). The ACL as well as each ACE * zero or more access control entries (ACEs). The ACL as well as each ACE
* are aligned on 4-byte boundaries. * are aligned on 4-byte boundaries.
*/ */
typedef struct { typedef struct
{
u8 revision; /* Revision of this ACL. */ u8 revision; /* Revision of this ACL. */
u8 alignment1; u8 alignment1;
u16 size; /* Allocated space in bytes for ACL. Includes this u16 size; /* Allocated space in bytes for ACL. Includes this
@ -1691,7 +1752,8 @@ typedef struct {
/** /**
* enum ACL_CONSTANTS - Current constants for ACLs. * enum ACL_CONSTANTS - Current constants for ACLs.
*/ */
typedef enum { typedef enum
{
/* Current revision. */ /* Current revision. */
ACL_REVISION = 2, ACL_REVISION = 2,
ACL_REVISION_DS = 4, ACL_REVISION_DS = 4,
@ -1754,7 +1816,8 @@ typedef enum {
* and all pointer fields are expressed as offsets from the * and all pointer fields are expressed as offsets from the
* beginning of the security descriptor. * beginning of the security descriptor.
*/ */
typedef enum { typedef enum
{
SE_OWNER_DEFAULTED = const_cpu_to_le16( 0x0001 ), SE_OWNER_DEFAULTED = const_cpu_to_le16( 0x0001 ),
SE_GROUP_DEFAULTED = const_cpu_to_le16( 0x0002 ), SE_GROUP_DEFAULTED = const_cpu_to_le16( 0x0002 ),
SE_DACL_PRESENT = const_cpu_to_le16( 0x0004 ), SE_DACL_PRESENT = const_cpu_to_le16( 0x0004 ),
@ -1777,7 +1840,8 @@ typedef enum {
* Self-relative security descriptor. Contains the owner and group SIDs as well * Self-relative security descriptor. Contains the owner and group SIDs as well
* as the sacl and dacl ACLs inside the security descriptor itself. * as the sacl and dacl ACLs inside the security descriptor itself.
*/ */
typedef struct { typedef struct
{
u8 revision; /* Revision level of the security descriptor. */ u8 revision; /* Revision level of the security descriptor. */
u8 alignment; u8 alignment;
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
@ -1809,7 +1873,8 @@ typedef struct {
* *
* On disk, a self-relative security descriptor is used. * On disk, a self-relative security descriptor is used.
*/ */
typedef struct { typedef struct
{
u8 revision; /* Revision level of the security descriptor. */ u8 revision; /* Revision level of the security descriptor. */
u8 alignment; u8 alignment;
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
@ -1835,7 +1900,8 @@ typedef struct {
* *
* Current constants for security descriptors. * Current constants for security descriptors.
*/ */
typedef enum { typedef enum
{
/* Current revision. */ /* Current revision. */
SECURITY_DESCRIPTOR_REVISION = 1, SECURITY_DESCRIPTOR_REVISION = 1,
SECURITY_DESCRIPTOR_REVISION1 = 1, SECURITY_DESCRIPTOR_REVISION1 = 1,
@ -1902,7 +1968,8 @@ typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR;
* This header precedes each security descriptor in the $SDS data stream. * This header precedes each security descriptor in the $SDS data stream.
* This is also the index entry data part of both the $SII and $SDH indexes. * This is also the index entry data part of both the $SII and $SDH indexes.
*/ */
typedef struct { typedef struct
{
u32 hash; /* Hash of the security descriptor. */ u32 hash; /* Hash of the security descriptor. */
u32 security_id; /* The security_id assigned to the descriptor. */ u32 security_id; /* The security_id assigned to the descriptor. */
u64 offset; /* Byte offset of this entry in the $SDS stream. */ u64 offset; /* Byte offset of this entry in the $SDS stream. */
@ -1912,7 +1979,8 @@ typedef struct {
/** /**
* struct SDH_INDEX_DATA - * struct SDH_INDEX_DATA -
*/ */
typedef struct { typedef struct
{
u32 hash; /* Hash of the security descriptor. */ u32 hash; /* Hash of the security descriptor. */
u32 security_id; /* The security_id assigned to the descriptor. */ u32 security_id; /* The security_id assigned to the descriptor. */
u64 offset; /* Byte offset of this entry in the $SDS stream. */ u64 offset; /* Byte offset of this entry in the $SDS stream. */
@ -1939,7 +2007,8 @@ typedef SECURITY_DESCRIPTOR_HEADER SII_INDEX_DATA;
* the first copy of the security descriptor will be at offset 0x51d0 in the * the first copy of the security descriptor will be at offset 0x51d0 in the
* $SDS data stream and the second copy will be at offset 0x451d0. * $SDS data stream and the second copy will be at offset 0x451d0.
*/ */
typedef struct { typedef struct
{
/* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like /* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like
unnamed structs. */ unnamed structs. */
u32 hash; /* Hash of the security descriptor. */ u32 hash; /* Hash of the security descriptor. */
@ -1955,7 +2024,8 @@ typedef struct {
* *
* The collation type is COLLATION_NTOFS_ULONG. * The collation type is COLLATION_NTOFS_ULONG.
*/ */
typedef struct { typedef struct
{
u32 security_id; /* The security_id assigned to the descriptor. */ u32 security_id; /* The security_id assigned to the descriptor. */
} __attribute__( ( __packed__ ) ) SII_INDEX_KEY; } __attribute__( ( __packed__ ) ) SII_INDEX_KEY;
@ -1965,7 +2035,8 @@ typedef struct {
* The keys are sorted first by hash and then by security_id. * The keys are sorted first by hash and then by security_id.
* The collation rule is COLLATION_NTOFS_SECURITY_HASH. * The collation rule is COLLATION_NTOFS_SECURITY_HASH.
*/ */
typedef struct { typedef struct
{
u32 hash; /* Hash of the security descriptor. */ u32 hash; /* Hash of the security descriptor. */
u32 security_id; /* The security_id assigned to the descriptor. */ u32 security_id; /* The security_id assigned to the descriptor. */
} __attribute__( ( __packed__ ) ) SDH_INDEX_KEY; } __attribute__( ( __packed__ ) ) SDH_INDEX_KEY;
@ -1976,14 +2047,16 @@ typedef struct {
* NOTE: Always resident. * NOTE: Always resident.
* NOTE: Present only in FILE_Volume. * NOTE: Present only in FILE_Volume.
*/ */
typedef struct { typedef struct
{
ntfschar name[0]; /* The name of the volume in Unicode. */ ntfschar name[0]; /* The name of the volume in Unicode. */
} __attribute__( ( __packed__ ) ) VOLUME_NAME; } __attribute__( ( __packed__ ) ) VOLUME_NAME;
/** /**
* enum VOLUME_FLAGS - Possible flags for the volume (16-bit). * enum VOLUME_FLAGS - Possible flags for the volume (16-bit).
*/ */
typedef enum { typedef enum
{
VOLUME_IS_DIRTY = const_cpu_to_le16( 0x0001 ), VOLUME_IS_DIRTY = const_cpu_to_le16( 0x0001 ),
VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16( 0x0002 ), VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16( 0x0002 ),
VOLUME_UPGRADE_ON_MOUNT = const_cpu_to_le16( 0x0004 ), VOLUME_UPGRADE_ON_MOUNT = const_cpu_to_le16( 0x0004 ),
@ -2003,7 +2076,8 @@ typedef enum {
* NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses * NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses
* NTFS 1.2. I haven't personally seen other values yet. * NTFS 1.2. I haven't personally seen other values yet.
*/ */
typedef struct { typedef struct
{
u64 reserved; /* Not used (yet?). */ u64 reserved; /* Not used (yet?). */
u8 major_ver; /* Major version of the ntfs format. */ u8 major_ver; /* Major version of the ntfs format. */
u8 minor_ver; /* Minor version of the ntfs format. */ u8 minor_ver; /* Minor version of the ntfs format. */
@ -2017,14 +2091,16 @@ typedef struct {
* *
* Data contents of a file (i.e. the unnamed stream) or of a named stream. * Data contents of a file (i.e. the unnamed stream) or of a named stream.
*/ */
typedef struct { typedef struct
{
u8 data[0]; /* The file's data contents. */ u8 data[0]; /* The file's data contents. */
} __attribute__( ( __packed__ ) ) DATA_ATTR; } __attribute__( ( __packed__ ) ) DATA_ATTR;
/** /**
* enum INDEX_HEADER_FLAGS - Index header flags (8-bit). * enum INDEX_HEADER_FLAGS - Index header flags (8-bit).
*/ */
typedef enum { typedef enum
{
/* When index header is in an index root attribute: */ /* When index header is in an index root attribute: */
SMALL_INDEX = 0, /* The index is small enough to fit inside the SMALL_INDEX = 0, /* The index is small enough to fit inside the
index root attribute and there is no index index root attribute and there is no index
@ -2054,8 +2130,10 @@ typedef enum {
* relative to the start of the index header structure and not relative to the * relative to the start of the index header structure and not relative to the
* start of the index root or index allocation structures themselves. * start of the index root or index allocation structures themselves.
*/ */
typedef struct { typedef struct
/* 0*/ u32 entries_offset; /* Byte offset from the INDEX_HEADER to first {
/* 0*/
u32 entries_offset; /* Byte offset from the INDEX_HEADER to first
INDEX_ENTRY, aligned to 8-byte boundary. */ INDEX_ENTRY, aligned to 8-byte boundary. */
/* 4*/ u32 index_length; /* Data size in byte of the INDEX_ENTRY's, /* 4*/ u32 index_length; /* Data size in byte of the INDEX_ENTRY's,
including the INDEX_HEADER, aligned to 8. */ including the INDEX_HEADER, aligned to 8. */
@ -2094,8 +2172,10 @@ typedef struct {
* NOTE: The root directory (FILE_root) contains an entry for itself. Other * NOTE: The root directory (FILE_root) contains an entry for itself. Other
* directories do not contain entries for themselves, though. * directories do not contain entries for themselves, though.
*/ */
typedef struct { typedef struct
/* 0*/ ATTR_TYPES type; /* Type of the indexed attribute. Is {
/* 0*/
ATTR_TYPES type; /* Type of the indexed attribute. Is
$FILE_NAME for directories, zero $FILE_NAME for directories, zero
for view indexes. No other values for view indexes. No other values
allowed. */ allowed. */
@ -2123,7 +2203,8 @@ typedef struct {
* INDEX_BLOCK structure containing an index header, followed by a sequence of * INDEX_BLOCK structure containing an index header, followed by a sequence of
* index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER. * index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
*/ */
typedef struct { typedef struct
{
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
NTFS_RECORD_TYPES magic;/* Magic is "INDX". */ NTFS_RECORD_TYPES magic;/* Magic is "INDX". */
u16 usa_ofs; /* See NTFS_RECORD definition. */ u16 usa_ofs; /* See NTFS_RECORD definition. */
@ -2158,7 +2239,8 @@ typedef INDEX_BLOCK INDEX_ALLOCATION;
* COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the * COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the
* primary key / is not a key at all. (AIA) * primary key / is not a key at all. (AIA)
*/ */
typedef struct { typedef struct
{
u32 reparse_tag; /* Reparse point type (inc. flags). */ u32 reparse_tag; /* Reparse point type (inc. flags). */
MFT_REF file_id; /* Mft record of the file containing the MFT_REF file_id; /* Mft record of the file containing the
reparse point attribute. */ reparse point attribute. */
@ -2167,7 +2249,8 @@ typedef struct {
/** /**
* enum QUOTA_FLAGS - Quota flags (32-bit). * enum QUOTA_FLAGS - Quota flags (32-bit).
*/ */
typedef enum { typedef enum
{
/* The user quota flags. Names explain meaning. */ /* The user quota flags. Names explain meaning. */
QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32( 0x00000001 ), QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32( 0x00000001 ),
QUOTA_FLAG_LIMIT_REACHED = const_cpu_to_le32( 0x00000002 ), QUOTA_FLAG_LIMIT_REACHED = const_cpu_to_le32( 0x00000002 ),
@ -2211,7 +2294,8 @@ typedef enum {
* *
* The $Q index entry data is the quota control entry and is defined below. * The $Q index entry data is the quota control entry and is defined below.
*/ */
typedef struct { typedef struct
{
u32 version; /* Currently equals 2. */ u32 version; /* Currently equals 2. */
QUOTA_FLAGS flags; /* Flags describing this quota entry. */ QUOTA_FLAGS flags; /* Flags describing this quota entry. */
u64 bytes_used; /* How many bytes of the quota are in use. */ u64 bytes_used; /* How many bytes of the quota are in use. */
@ -2233,7 +2317,8 @@ typedef struct {
/** /**
* struct QUOTA_O_INDEX_DATA - * struct QUOTA_O_INDEX_DATA -
*/ */
typedef struct { typedef struct
{
u32 owner_id; u32 owner_id;
u32 unknown; /* Always 32. Seems to be padding and it's not u32 unknown; /* Always 32. Seems to be padding and it's not
counted in the INDEX_ENTRY's data_length. counted in the INDEX_ENTRY's data_length.
@ -2243,7 +2328,8 @@ typedef struct {
/** /**
* enum PREDEFINED_OWNER_IDS - Predefined owner_id values (32-bit). * enum PREDEFINED_OWNER_IDS - Predefined owner_id values (32-bit).
*/ */
typedef enum { typedef enum
{
QUOTA_INVALID_ID = const_cpu_to_le32( 0x00000000 ), QUOTA_INVALID_ID = const_cpu_to_le32( 0x00000000 ),
QUOTA_DEFAULTS_ID = const_cpu_to_le32( 0x00000001 ), QUOTA_DEFAULTS_ID = const_cpu_to_le32( 0x00000001 ),
QUOTA_FIRST_USER_ID = const_cpu_to_le32( 0x00000100 ), QUOTA_FIRST_USER_ID = const_cpu_to_le32( 0x00000100 ),
@ -2252,7 +2338,8 @@ typedef enum {
/** /**
* enum INDEX_ENTRY_FLAGS - Index entry flags (16-bit). * enum INDEX_ENTRY_FLAGS - Index entry flags (16-bit).
*/ */
typedef enum { typedef enum
{
INDEX_ENTRY_NODE = const_cpu_to_le16( 1 ), /* This entry contains a INDEX_ENTRY_NODE = const_cpu_to_le16( 1 ), /* This entry contains a
sub-node, i.e. a reference to an index sub-node, i.e. a reference to an index
block in form of a virtual cluster block in form of a virtual cluster
@ -2271,10 +2358,14 @@ typedef enum {
* !!!!! SEE DESCRIPTION OF THE FIELDS AT INDEX_ENTRY !!!!! * !!!!! SEE DESCRIPTION OF THE FIELDS AT INDEX_ENTRY !!!!!
* ========================================================== * ==========================================================
*/ */
typedef struct { typedef struct
/* 0*/ union { {
/* 0*/
union
{
MFT_REF indexed_file; MFT_REF indexed_file;
struct { struct
{
u16 data_offset; u16 data_offset;
u16 data_length; u16 data_length;
u32 reservedV; u32 reservedV;
@ -2296,14 +2387,17 @@ typedef struct {
* *
* NOTE: Before NTFS 3.0 only filename attributes were indexed. * NOTE: Before NTFS 3.0 only filename attributes were indexed.
*/ */
typedef struct { typedef struct
{
/* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */ /* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */
union { /* Only valid when INDEX_ENTRY_END is not set. */ union /* Only valid when INDEX_ENTRY_END is not set. */
{
MFT_REF indexed_file; /* The mft reference of the file MFT_REF indexed_file; /* The mft reference of the file
described by this index described by this index
entry. Used for directory entry. Used for directory
indexes. */ indexes. */
struct { /* Used for views/indexes to find the entry's data. */ struct /* Used for views/indexes to find the entry's data. */
{
u16 data_offset; /* Data byte offset from this u16 data_offset; /* Data byte offset from this
INDEX_ENTRY. Follows the INDEX_ENTRY. Follows the
index key. */ index key. */
@ -2320,7 +2414,8 @@ typedef struct {
/* 12*/ INDEX_ENTRY_FLAGS ie_flags; /* Bit field of INDEX_ENTRY_* flags. */ /* 12*/ INDEX_ENTRY_FLAGS ie_flags; /* Bit field of INDEX_ENTRY_* flags. */
/* 14*/ u16 reserved; /* Reserved/align to 8-byte boundary. */ /* 14*/ u16 reserved; /* Reserved/align to 8-byte boundary. */
/* End of INDEX_ENTRY_HEADER */ /* End of INDEX_ENTRY_HEADER */
/* 16*/ union { /* The key of the indexed attribute. NOTE: Only present /* 16*/ union
{ /* The key of the indexed attribute. NOTE: Only present
if INDEX_ENTRY_END bit in flags is not set. NOTE: On if INDEX_ENTRY_END bit in flags is not set. NOTE: On
NTFS versions before 3.0 the only valid key is the NTFS versions before 3.0 the only valid key is the
FILE_NAME_ATTR. On NTFS 3.0+ the following FILE_NAME_ATTR. On NTFS 3.0+ the following
@ -2364,7 +2459,8 @@ typedef struct {
* the number of bits in the bitmap * index block size / cluster size is the * the number of bits in the bitmap * index block size / cluster size is the
* number of clusters in the index allocation attribute. * number of clusters in the index allocation attribute.
*/ */
typedef struct { typedef struct
{
u8 bitmap[0]; /* Array of bits. */ u8 bitmap[0]; /* Array of bits. */
} __attribute__( ( __packed__ ) ) BITMAP_ATTR; } __attribute__( ( __packed__ ) ) BITMAP_ATTR;
@ -2388,7 +2484,8 @@ typedef struct {
* bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User * bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
* defined tags have to use zero here. * defined tags have to use zero here.
*/ */
typedef enum { typedef enum
{
IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32( 0x20000000 ), IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32( 0x20000000 ),
IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32( 0x40000000 ), IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32( 0x40000000 ),
IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32( 0x80000000 ), IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32( 0x80000000 ),
@ -2416,7 +2513,8 @@ typedef enum {
* *
* NOTE: Can be resident or non-resident. * NOTE: Can be resident or non-resident.
*/ */
typedef struct { typedef struct
{
u32 reparse_tag; /* Reparse point type (inc. flags). */ u32 reparse_tag; /* Reparse point type (inc. flags). */
u16 reparse_data_length; /* Byte size of reparse data. */ u16 reparse_data_length; /* Byte size of reparse data. */
u16 reserved; /* Align to 8-byte boundary. */ u16 reserved; /* Align to 8-byte boundary. */
@ -2428,7 +2526,8 @@ typedef struct {
* *
* NOTE: Always resident. * NOTE: Always resident.
*/ */
typedef struct { typedef struct
{
u16 ea_length; /* Byte size of the packed extended u16 ea_length; /* Byte size of the packed extended
attributes. */ attributes. */
u16 need_ea_count; /* The number of extended attributes which have u16 need_ea_count; /* The number of extended attributes which have
@ -2443,7 +2542,8 @@ typedef struct {
/** /**
* enum EA_FLAGS - Extended attribute flags (8-bit). * enum EA_FLAGS - Extended attribute flags (8-bit).
*/ */
typedef enum { typedef enum
{
NEED_EA = 0x80, /* Indicate that the file to which the EA NEED_EA = 0x80, /* Indicate that the file to which the EA
belongs cannot be interpreted without belongs cannot be interpreted without
understanding the associated extended understanding the associated extended
@ -2459,7 +2559,8 @@ typedef enum {
* FIXME: It appears weird that the EA name is not Unicode. Is it true? * FIXME: It appears weird that the EA name is not Unicode. Is it true?
* FIXME: It seems that name is always uppercased. Is it true? * FIXME: It seems that name is always uppercased. Is it true?
*/ */
typedef struct { typedef struct
{
u32 next_entry_offset; /* Offset to the next EA_ATTR. */ u32 next_entry_offset; /* Offset to the next EA_ATTR. */
EA_FLAGS flags; /* Flags describing the EA. */ EA_FLAGS flags; /* Flags describing the EA. */
u8 name_length; /* Length of the name of the extended u8 name_length; /* Length of the name of the extended
@ -2476,7 +2577,8 @@ typedef struct {
* Intended to support Native Structure Storage (NSS) - a feature removed from * Intended to support Native Structure Storage (NSS) - a feature removed from
* NTFS 3.0 during beta testing. * NTFS 3.0 during beta testing.
*/ */
typedef struct { typedef struct
{
/* Irrelevant as feature unused. */ /* Irrelevant as feature unused. */
} __attribute__( ( __packed__ ) ) PROPERTY_SET; } __attribute__( ( __packed__ ) ) PROPERTY_SET;
@ -2491,7 +2593,8 @@ typedef struct {
* Used by the Encrypting File System (EFS). All encrypted files have this * Used by the Encrypting File System (EFS). All encrypted files have this
* attribute with the name $EFS. See below for the relevant structures. * attribute with the name $EFS. See below for the relevant structures.
*/ */
typedef struct { typedef struct
{
/* Can be anything the creator chooses. */ /* Can be anything the creator chooses. */
} __attribute__( ( __packed__ ) ) LOGGED_UTILITY_STREAM; } __attribute__( ( __packed__ ) ) LOGGED_UTILITY_STREAM;
@ -2527,8 +2630,10 @@ typedef struct {
* *
* The header of the Logged utility stream (0x100) attribute named "$EFS". * The header of the Logged utility stream (0x100) attribute named "$EFS".
*/ */
typedef struct { typedef struct
/* 0*/ u32 length; /* Length of EFS attribute in bytes. */ {
/* 0*/
u32 length; /* Length of EFS attribute in bytes. */
u32 state; /* Always 0? */ u32 state; /* Always 0? */
u32 version; /* Efs version. Always 2? */ u32 version; /* Efs version. Always 2? */
u32 crypto_api_version; /* Always 0? */ u32 crypto_api_version; /* Always 0? */
@ -2551,7 +2656,8 @@ typedef struct {
/** /**
* struct EFS_DF_ARRAY_HEADER - * struct EFS_DF_ARRAY_HEADER -
*/ */
typedef struct { typedef struct
{
u32 df_count; /* Number of data decryption/recovery fields in u32 df_count; /* Number of data decryption/recovery fields in
the array. */ the array. */
} __attribute__( ( __packed__ ) ) EFS_DF_ARRAY_HEADER; } __attribute__( ( __packed__ ) ) EFS_DF_ARRAY_HEADER;
@ -2559,8 +2665,10 @@ typedef struct {
/** /**
* struct EFS_DF_HEADER - * struct EFS_DF_HEADER -
*/ */
typedef struct { typedef struct
/* 0*/ u32 df_length; /* Length of this data decryption/recovery {
/* 0*/
u32 df_length; /* Length of this data decryption/recovery
field in bytes. */ field in bytes. */
u32 cred_header_offset; /* Offset in bytes to the credential header. */ u32 cred_header_offset; /* Offset in bytes to the credential header. */
u32 fek_size; /* Size in bytes of the encrypted file u32 fek_size; /* Size in bytes of the encrypted file
@ -2573,8 +2681,10 @@ typedef struct {
/** /**
* struct EFS_DF_CREDENTIAL_HEADER - * struct EFS_DF_CREDENTIAL_HEADER -
*/ */
typedef struct { typedef struct
/* 0*/ u32 cred_length; /* Length of this credential in bytes. */ {
/* 0*/
u32 cred_length; /* Length of this credential in bytes. */
u32 sid_offset; /* Offset in bytes to the user's sid from start u32 sid_offset; /* Offset in bytes to the user's sid from start
of this structure. Zero if no sid is of this structure. Zero if no sid is
present. */ present. */
@ -2583,10 +2693,13 @@ typedef struct {
2 = Unexpected type. 2 = Unexpected type.
3 = Certificate thumbprint. 3 = Certificate thumbprint.
other = Unknown type. */ other = Unknown type. */
union { union
{
/* CryptoAPI container. */ /* CryptoAPI container. */
struct { struct
/* 12*/ u32 container_name_offset; /* Offset in bytes to {
/* 12*/
u32 container_name_offset; /* Offset in bytes to
the name of the container from start of this the name of the container from start of this
structure (may not be zero). */ structure (may not be zero). */
/* 16*/ u32 provider_name_offset; /* Offset in bytes to /* 16*/ u32 provider_name_offset; /* Offset in bytes to
@ -2599,8 +2712,10 @@ typedef struct {
public key blob. */ public key blob. */
} __attribute__( ( __packed__ ) ); } __attribute__( ( __packed__ ) );
/* Certificate thumbprint. */ /* Certificate thumbprint. */
struct { struct
/* 12*/ u32 cert_thumbprint_header_size; /* Size in {
/* 12*/
u32 cert_thumbprint_header_size; /* Size in
bytes of the header of the certificate bytes of the header of the certificate
thumbprint. */ thumbprint. */
/* 16*/ u32 cert_thumbprint_header_offset; /* Offset in /* 16*/ u32 cert_thumbprint_header_offset; /* Offset in
@ -2617,8 +2732,10 @@ typedef EFS_DF_CREDENTIAL_HEADER EFS_DF_CRED_HEADER;
/** /**
* struct EFS_DF_CERTIFICATE_THUMBPRINT_HEADER - * struct EFS_DF_CERTIFICATE_THUMBPRINT_HEADER -
*/ */
typedef struct { typedef struct
/* 0*/ u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */ {
/* 0*/
u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */
u32 thumbprint_size; /* Size of thumbprint in bytes. */ u32 thumbprint_size; /* Size of thumbprint in bytes. */
/* 8*/ u32 container_name_offset; /* Offset in bytes to the name of the /* 8*/ u32 container_name_offset; /* Offset in bytes to the name of the
container from start of this container from start of this
@ -2635,7 +2752,8 @@ typedef struct {
typedef EFS_DF_CERTIFICATE_THUMBPRINT_HEADER EFS_DF_CERT_THUMBPRINT_HEADER; typedef EFS_DF_CERTIFICATE_THUMBPRINT_HEADER EFS_DF_CERT_THUMBPRINT_HEADER;
typedef enum { typedef enum
{
INTX_SYMBOLIC_LINK = INTX_SYMBOLIC_LINK =
const_cpu_to_le64( 0x014B4E4C78746E49ULL ), /* "IntxLNK\1" */ const_cpu_to_le64( 0x014B4E4C78746E49ULL ), /* "IntxLNK\1" */
INTX_CHARACTER_DEVICE = INTX_CHARACTER_DEVICE =
@ -2644,11 +2762,14 @@ typedef enum {
const_cpu_to_le64( 0x004B4C4278746E49ULL ), /* "IntxBLK\0" */ const_cpu_to_le64( 0x004B4C4278746E49ULL ), /* "IntxBLK\0" */
} INTX_FILE_TYPES; } INTX_FILE_TYPES;
typedef struct { typedef struct
{
INTX_FILE_TYPES magic; /* Intx file magic. */ INTX_FILE_TYPES magic; /* Intx file magic. */
union { union
{
/* For character and block devices. */ /* For character and block devices. */
struct { struct
{
u64 major; /* Major device number. */ u64 major; /* Major device number. */
u64 minor; /* Minor device number. */ u64 minor; /* Minor device number. */
void *device_end[0]; /* Marker for offsetof(). */ void *device_end[0]; /* Marker for offsetof(). */

View File

@ -55,7 +55,8 @@
#define NTFS_LCNALLOC_BSIZE 4096 #define NTFS_LCNALLOC_BSIZE 4096
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE #define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
enum { enum
{
ZONE_MFT = 1, ZONE_MFT = 1,
ZONE_DATA1 = 2, ZONE_DATA1 = 2,
ZONE_DATA2 = 4 ZONE_DATA2 = 4
@ -94,19 +95,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 ) static void update_full_status( ntfs_volume *vol, LCN lcn )
{ {
if (lcn >= vol->mft_zone_end) { if ( lcn >= vol->mft_zone_end )
if (vol->full_zones & ZONE_DATA1) { {
if ( vol->full_zones & ZONE_DATA1 )
{
ntfs_cluster_update_zone_pos( vol, ZONE_DATA1, lcn ); ntfs_cluster_update_zone_pos( vol, ZONE_DATA1, lcn );
vol->full_zones &= ~ZONE_DATA1; vol->full_zones &= ~ZONE_DATA1;
} }
} else }
if (lcn < vol->mft_zone_start) { else if ( lcn < vol->mft_zone_start )
if (vol->full_zones & ZONE_DATA2) { {
if ( vol->full_zones & ZONE_DATA2 )
{
ntfs_cluster_update_zone_pos( vol, ZONE_DATA2, lcn ); ntfs_cluster_update_zone_pos( vol, ZONE_DATA2, lcn );
vol->full_zones &= ~ZONE_DATA2; 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 ); ntfs_cluster_update_zone_pos( vol, ZONE_MFT, lcn );
vol->full_zones &= ~ZONE_MFT; vol->full_zones &= ~ZONE_MFT;
} }
@ -122,38 +130,49 @@ static s64 max_empty_bit_range(unsigned char *buf, int size)
ntfs_log_trace( "Entering\n" ); ntfs_log_trace( "Entering\n" );
i = 0; i = 0;
while (i < size) { while ( i < size )
switch (*buf) { {
switch ( *buf )
{
case 0 : case 0 :
do { do
{
buf++; buf++;
run += 8; run += 8;
i++; i++;
} while ((i < size) && !*buf); }
while ( ( i < size ) && !*buf );
break; break;
case 255 : case 255 :
if (run > max_range) { if ( run > max_range )
{
max_range = run; max_range = run;
start_pos = ( s64 )i * 8 - run; start_pos = ( s64 )i * 8 - run;
} }
run = 0; run = 0;
do { do
{
buf++; buf++;
i++; i++;
} while ((i < size) && (*buf == 255)); }
while ( ( i < size ) && ( *buf == 255 ) );
break; break;
default : default :
for (j = 0; j < 8; j++) { for ( j = 0; j < 8; j++ )
{
int bit = *buf & ( 1 << j ); int bit = *buf & ( 1 << j );
if (bit) { if ( bit )
if (run > max_range) { {
if ( run > max_range )
{
max_range = run; max_range = run;
start_pos = ( s64 )i * 8 + ( j - run ); start_pos = ( s64 )i * 8 + ( j - run );
} }
run = 0; run = 0;
} else }
else
run++; run++;
} }
i++; i++;
@ -181,7 +200,8 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
*writeback = 0; *writeback = 0;
written = ntfs_attr_pwrite( vol->lcnbmp_na, pos, size, b ); written = ntfs_attr_pwrite( vol->lcnbmp_na, pos, size, b );
if (written != size) { if ( written != size )
{
if ( !written ) if ( !written )
errno = EIO; errno = EIO;
ntfs_log_perror( "Bitmap write error (%lld, %lld)", ntfs_log_perror( "Bitmap write error (%lld, %lld)",
@ -253,7 +273,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA" ); start_lcn, zone == MFT_ZONE ? "MFT" : "DATA" );
if ( !vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na || if ( !vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
(s8)zone < FIRST_ZONE || zone > LAST_ZONE) { ( s8 )zone < FIRST_ZONE || zone > LAST_ZONE )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: vcn: %lld, count: %lld, lcn: %lld", ntfs_log_perror( "%s: vcn: %lld, count: %lld, lcn: %lld",
__FUNCTION__, ( long long )start_vcn, __FUNCTION__, ( long long )start_vcn,
@ -262,9 +283,11 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
} }
/* Return empty runlist if @count == 0 */ /* Return empty runlist if @count == 0 */
if (!count) { if ( !count )
{
rl = ntfs_malloc( 0x1000 ); rl = ntfs_malloc( 0x1000 );
if (rl) { if ( rl )
{
rl[0].vcn = start_vcn; rl[0].vcn = start_vcn;
rl[0].lcn = LCN_RL_NOT_MAPPED; rl[0].lcn = LCN_RL_NOT_MAPPED;
rl[0].length = 0; rl[0].length = 0;
@ -282,7 +305,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
has_guess = 1; has_guess = 1;
zone_start = start_lcn; zone_start = start_lcn;
if (zone_start < 0) { if ( zone_start < 0 )
{
if ( zone == DATA_ZONE ) if ( zone == DATA_ZONE )
zone_start = vol->data1_zone_pos; zone_start = vol->data1_zone_pos;
else else
@ -296,13 +320,18 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
zone_start == vol->mft_zone_end ) zone_start == vol->mft_zone_end )
pass = 2; pass = 2;
if (zone_start < vol->mft_zone_start) { if ( zone_start < vol->mft_zone_start )
{
zone_end = vol->mft_zone_start; zone_end = vol->mft_zone_start;
search_zone = ZONE_DATA2; 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; zone_end = vol->mft_zone_end;
search_zone = ZONE_MFT; search_zone = ZONE_MFT;
} else { }
else
{
zone_end = vol->nr_clusters; zone_end = vol->nr_clusters;
search_zone = ZONE_DATA1; search_zone = ZONE_DATA1;
} }
@ -312,14 +341,16 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
/* Loop until all clusters are allocated. */ /* Loop until all clusters are allocated. */
clusters = count; clusters = count;
rlpos = rlsize = 0; rlpos = rlsize = 0;
while (1) { while ( 1 )
{
/* check whether we have exhausted the current zone */ /* check whether we have exhausted the current zone */
if ( search_zone & vol->full_zones ) if ( search_zone & vol->full_zones )
goto zone_pass_done; goto zone_pass_done;
last_read_pos = bmp_pos >> 3; last_read_pos = bmp_pos >> 3;
br = ntfs_attr_pread( vol->lcnbmp_na, last_read_pos, br = ntfs_attr_pread( vol->lcnbmp_na, last_read_pos,
NTFS_LCNALLOC_BSIZE, buf ); NTFS_LCNALLOC_BSIZE, buf );
if (br <= 0) { if ( br <= 0 )
{
if ( !br ) if ( !br )
goto zone_pass_done; goto zone_pass_done;
err = errno; err = errno;
@ -335,15 +366,20 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
bmp_pos &= ~7; bmp_pos &= ~7;
writeback = 0; writeback = 0;
while (lcn < buf_size) { while ( lcn < buf_size )
{
byte = buf + ( lcn >> 3 ); byte = buf + ( lcn >> 3 );
bit = 1 << ( lcn & 7 ); bit = 1 << ( lcn & 7 );
if (has_guess) { if ( has_guess )
if (*byte & bit) { {
if ( *byte & bit )
{
has_guess = 0; has_guess = 0;
break; break;
} }
} else { }
else
{
lcn = max_empty_bit_range( buf, br ); lcn = max_empty_bit_range( buf, br );
if ( lcn < 0 ) if ( lcn < 0 )
break; break;
@ -354,10 +390,12 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
/* First free bit is at lcn + bmp_pos. */ /* First free bit is at lcn + bmp_pos. */
/* Reallocate memory if necessary. */ /* Reallocate memory if necessary. */
if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) { if ( ( rlpos + 2 ) * ( int )sizeof( runlist ) >= rlsize )
{
rlsize += 4096; rlsize += 4096;
trl = realloc( rl, rlsize ); trl = realloc( rl, rlsize );
if (!trl) { if ( !trl )
{
err = ENOMEM; err = ENOMEM;
ntfs_log_perror( "realloc() failed" ); ntfs_log_perror( "realloc() failed" );
goto wb_err_ret; goto wb_err_ret;
@ -379,7 +417,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
* Coalesce with previous run if adjacent LCNs. * Coalesce with previous run if adjacent LCNs.
* Otherwise, append a new run. * 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: " ntfs_log_debug( "Cluster coalesce: prev_lcn: "
"%lld lcn: %lld bmp_pos: %lld " "%lld lcn: %lld bmp_pos: %lld "
"prev_run_len: %lld\n", "prev_run_len: %lld\n",
@ -387,11 +426,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
( long long )lcn, ( long long )bmp_pos, ( long long )lcn, ( long long )bmp_pos,
( long long )prev_run_len ); ( long long )prev_run_len );
rl[rlpos - 1].length = ++prev_run_len; rl[rlpos - 1].length = ++prev_run_len;
} else { }
else
{
if ( rlpos ) if ( rlpos )
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos].vcn = rl[rlpos - 1].vcn +
prev_run_len; prev_run_len;
else { else
{
rl[rlpos].vcn = start_vcn; rl[rlpos].vcn = start_vcn;
ntfs_log_debug( "Start_vcn: %lld\n", ntfs_log_debug( "Start_vcn: %lld\n",
( long long )start_vcn ); ( long long )start_vcn );
@ -407,7 +449,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
( long long )rl[rlpos - 1].lcn, ( long long )rl[rlpos - 1].lcn,
( long long )rl[rlpos - 1].length ); ( long long )rl[rlpos - 1].length );
/* Done? */ /* Done? */
if (!--clusters) { if ( !--clusters )
{
if ( used_zone_pos ) if ( used_zone_pos )
ntfs_cluster_update_zone_pos( vol, ntfs_cluster_update_zone_pos( vol,
search_zone, lcn + bmp_pos + 1 + search_zone, lcn + bmp_pos + 1 +
@ -418,12 +461,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
lcn++; lcn++;
} }
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) { if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
{
err = errno; err = errno;
goto err_ret; goto err_ret;
} }
if (!used_zone_pos) { if ( !used_zone_pos )
{
used_zone_pos = 1; used_zone_pos = 1;
@ -438,7 +483,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
zone_start == vol->mft_zone_end ) zone_start == vol->mft_zone_end )
pass = 2; pass = 2;
bmp_pos = zone_start; bmp_pos = zone_start;
} else }
else
bmp_pos += buf_size; bmp_pos += buf_size;
if ( bmp_pos < zone_end ) if ( bmp_pos < zone_end )
@ -446,7 +492,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
zone_pass_done: zone_pass_done:
ntfs_log_trace( "Finished current zone pass(%i).\n", pass ); ntfs_log_trace( "Finished current zone pass(%i).\n", pass );
if (pass == 1) { if ( pass == 1 )
{
pass = 2; pass = 2;
zone_end = zone_start; zone_end = zone_start;
@ -469,10 +516,12 @@ zone_pass_done:
done_zones_check: done_zones_check:
done_zones |= search_zone; done_zones |= search_zone;
vol->full_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" ); ntfs_log_trace( "Switching zone.\n" );
pass = 1; pass = 1;
if (rlpos) { if ( rlpos )
{
LCN tc = rl[rlpos - 1].lcn + LCN tc = rl[rlpos - 1].lcn +
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP; rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
@ -481,7 +530,8 @@ done_zones_check:
search_zone, tc ); search_zone, tc );
} }
switch (search_zone) { switch ( search_zone )
{
case ZONE_MFT: case ZONE_MFT:
ntfs_log_trace( "Zone switch: mft -> data1\n" ); ntfs_log_trace( "Zone switch: mft -> data1\n" );
switch_to_data1_zone: search_zone = ZONE_DATA1; switch_to_data1_zone: search_zone = ZONE_DATA1;
@ -499,7 +549,8 @@ switch_to_data1_zone: search_zone = ZONE_DATA1;
pass = 2; pass = 2;
break; break;
case ZONE_DATA2: case ZONE_DATA2:
if (!(done_zones & ZONE_DATA1)) { if ( !( done_zones & ZONE_DATA1 ) )
{
ntfs_log_trace( "data2 -> data1\n" ); ntfs_log_trace( "data2 -> data1\n" );
goto switch_to_data1_zone; goto switch_to_data1_zone;
} }
@ -514,7 +565,8 @@ switch_to_data1_zone: search_zone = ZONE_DATA1;
bmp_pos = zone_start; bmp_pos = zone_start;
if (zone_start == zone_end) { if ( zone_start == zone_end )
{
ntfs_log_trace( "Empty zone, skipped.\n" ); ntfs_log_trace( "Empty zone, skipped.\n" );
goto done_zones_check; goto done_zones_check;
} }
@ -532,13 +584,15 @@ done_ret:
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
rl[rlpos].lcn = LCN_RL_NOT_MAPPED; rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
rl[rlpos].length = 0; 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; err = errno;
goto err_ret; goto err_ret;
} }
done_err_ret: done_err_ret:
free( buf ); free( buf );
if (err) { if ( err )
{
errno = err; errno = err;
ntfs_log_perror( "Failed to allocate clusters" ); ntfs_log_perror( "Failed to allocate clusters" );
rl = NULL; rl = NULL;
@ -553,7 +607,8 @@ wb_err_ret:
err = errno; err = errno;
err_ret: err_ret:
ntfs_log_trace( "At err_ret.\n" ); ntfs_log_trace( "At err_ret.\n" );
if (rl) { if ( rl )
{
/* Add runlist terminator element. */ /* Add runlist terminator element. */
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
rl[rlpos].lcn = LCN_RL_NOT_MAPPED; rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
@ -580,15 +635,18 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
ntfs_log_trace( "Entering.\n" ); ntfs_log_trace( "Entering.\n" );
for (; rl->length; rl++) { for ( ; rl->length; rl++ )
{
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n", ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
( long long )rl->lcn, ( long long )rl->length ); ( long long )rl->lcn, ( long long )rl->length );
if (rl->lcn >= 0) { if ( rl->lcn >= 0 )
{
update_full_status( vol, rl->lcn ); update_full_status( vol, rl->lcn );
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn, if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
rl->length)) { rl->length ) )
{
ntfs_log_perror( "Cluster deallocation failed " ntfs_log_perror( "Cluster deallocation failed "
"(%lld, %lld)", "(%lld, %lld)",
( long long )rl->lcn, ( long long )rl->lcn,
@ -623,10 +681,12 @@ int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count)
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n", ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
( long long )lcn, ( long long )count ); ( long long )lcn, ( long long )count );
if (lcn >= 0) { if ( lcn >= 0 )
{
update_full_status( vol, lcn ); update_full_status( vol, lcn );
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, lcn, if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, lcn,
count)) { count ) )
{
ntfs_log_perror( "Cluster deallocation failed " ntfs_log_perror( "Cluster deallocation failed "
"(%lld, %lld)", "(%lld, %lld)",
( long long )lcn, ( long long )lcn,
@ -668,7 +728,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
int ret = -1; int ret = -1;
if ( !vol || !vol->lcnbmp_na || !na || start_vcn < 0 || if ( !vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
(count < 0 && count != -1)) { ( count < 0 && count != -1 ) )
{
ntfs_log_trace( "Invalid arguments!\n" ); ntfs_log_trace( "Invalid arguments!\n" );
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -679,13 +740,15 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
na->type, ( long long )count, ( long long )start_vcn ); na->type, ( long long )count, ( long long )start_vcn );
rl = ntfs_attr_find_vcn( na, start_vcn ); rl = ntfs_attr_find_vcn( na, start_vcn );
if (!rl) { if ( !rl )
{
if ( errno == ENOENT ) if ( errno == ENOENT )
ret = 0; ret = 0;
goto leave; goto leave;
} }
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { if ( rl->lcn < 0 && rl->lcn != LCN_HOLE )
{
errno = EIO; errno = EIO;
ntfs_log_perror( "%s: Unexpected lcn (%lld)", __FUNCTION__, ntfs_log_perror( "%s: Unexpected lcn (%lld)", __FUNCTION__,
( long long )rl->lcn ); ( long long )rl->lcn );
@ -700,7 +763,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
if ( count >= 0 && to_free > count ) if ( count >= 0 && to_free > count )
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. */ /* Do the actual freeing of the clusters in this run. */
update_full_status( vol, rl->lcn + delta ); update_full_status( vol, rl->lcn + delta );
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn + delta, if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn + delta,
@ -718,10 +782,12 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
* Loop over the remaining runs, using @count as a capping value, and * Loop over the remaining runs, using @count as a capping value, and
* free them. * free them.
*/ */
for (; rl->length && count != 0; ++rl) { for ( ; rl->length && count != 0; ++rl )
{
// FIXME: Need to try ntfs_attr_map_runlist() for attribute // FIXME: Need to try ntfs_attr_map_runlist() for attribute
// list support! (AIA) // 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) // FIXME: Eeek! We need rollback! (AIA)
errno = EIO; errno = EIO;
ntfs_log_perror( "%s: Invalid lcn (%lli)", ntfs_log_perror( "%s: Invalid lcn (%lli)",
@ -734,10 +800,12 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
if ( count >= 0 && to_free > count ) if ( count >= 0 && to_free > count )
to_free = count; to_free = count;
if (rl->lcn != LCN_HOLE) { if ( rl->lcn != LCN_HOLE )
{
update_full_status( vol, rl->lcn ); update_full_status( vol, rl->lcn );
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn, if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
to_free)) { to_free ) )
{
// FIXME: Eeek! We need rollback! (AIA) // FIXME: Eeek! We need rollback! (AIA)
ntfs_log_perror( "%s: Clearing bitmap run failed", ntfs_log_perror( "%s: Clearing bitmap run failed",
__FUNCTION__ ); __FUNCTION__ );
@ -750,7 +818,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
count -= to_free; count -= to_free;
} }
if (count != -1 && count != 0) { if ( count != -1 && count != 0 )
{
// FIXME: Eeek! BUG() // FIXME: Eeek! BUG()
errno = EIO; errno = EIO;
ntfs_log_perror( "%s: count still not zero (%lld)", __FUNCTION__, ntfs_log_perror( "%s: count still not zero (%lld)", __FUNCTION__,

View File

@ -31,7 +31,8 @@
/** /**
* enum NTFS_CLUSTER_ALLOCATION_ZONES - * enum NTFS_CLUSTER_ALLOCATION_ZONES -
*/ */
typedef enum { typedef enum
{
FIRST_ZONE = 0, /* For sanity checking. */ FIRST_ZONE = 0, /* For sanity checking. */
MFT_ZONE = 0, /* Allocate from $MFT zone. */ MFT_ZONE = 0, /* Allocate from $MFT zone. */
DATA_ZONE = 1, /* Allocate from $DATA zone. */ DATA_ZONE = 1, /* Allocate from $DATA zone. */

View File

@ -71,7 +71,8 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
logfile_log_page_size < NTFS_BLOCK_SIZE || logfile_log_page_size < NTFS_BLOCK_SIZE ||
logfile_system_page_size & logfile_system_page_size &
( logfile_system_page_size - 1 ) || ( logfile_system_page_size - 1 ) ||
logfile_log_page_size & (logfile_log_page_size - 1)) { logfile_log_page_size & ( logfile_log_page_size - 1 ) )
{
ntfs_log_error( "$LogFile uses unsupported page size.\n" ); ntfs_log_error( "$LogFile uses unsupported page size.\n" );
return FALSE; return FALSE;
} }
@ -79,14 +80,16 @@ 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 * We must be either at !pos (1st restart page) or at pos = system page
* size (2nd restart 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 " ntfs_log_error( "Found restart area in incorrect "
"position in $LogFile.\n" ); "position in $LogFile.\n" );
return FALSE; return FALSE;
} }
/* We only know how to handle version 1.1. */ /* We only know how to handle version 1.1. */
if ( sle16_to_cpu( rp->major_ver ) != 1 || if ( sle16_to_cpu( rp->major_ver ) != 1 ||
sle16_to_cpu(rp->minor_ver) != 1) { sle16_to_cpu( rp->minor_ver ) != 1 )
{
ntfs_log_error( "$LogFile version %i.%i is not " ntfs_log_error( "$LogFile version %i.%i is not "
"supported. (This driver supports version " "supported. (This driver supports version "
"1.1 only.)\n", ( int )sle16_to_cpu( rp->major_ver ), "1.1 only.)\n", ( int )sle16_to_cpu( rp->major_ver ),
@ -97,13 +100,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 * If chkdsk has been run the restart page may not be protected by an
* update sequence array. * 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; have_usa = FALSE;
goto skip_usa_checks; goto skip_usa_checks;
} }
/* Verify the size of the update sequence array. */ /* Verify the size of the update sequence array. */
usa_count = 1 + ( logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS ); 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 " ntfs_log_error( "$LogFile restart page specifies "
"inconsistent update sequence array count.\n" ); "inconsistent update sequence array count.\n" );
return FALSE; return FALSE;
@ -112,7 +117,8 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
usa_ofs = le16_to_cpu( rp->usa_ofs ); usa_ofs = le16_to_cpu( rp->usa_ofs );
usa_end = usa_ofs + usa_count * sizeof( u16 ); usa_end = usa_ofs + usa_count * sizeof( u16 );
if ( usa_ofs < sizeof( RESTART_PAGE_HEADER ) || if ( usa_ofs < sizeof( RESTART_PAGE_HEADER ) ||
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) { usa_end > NTFS_BLOCK_SIZE - sizeof( u16 ) )
{
ntfs_log_error( "$LogFile restart page specifies " ntfs_log_error( "$LogFile restart page specifies "
"inconsistent update sequence array offset.\n" ); "inconsistent update sequence array offset.\n" );
return FALSE; return FALSE;
@ -127,7 +133,8 @@ skip_usa_checks:
ra_ofs = le16_to_cpu( rp->restart_area_offset ); ra_ofs = le16_to_cpu( rp->restart_area_offset );
if ( ra_ofs & 7 || ( have_usa ? ra_ofs < usa_end : if ( ra_ofs & 7 || ( have_usa ? ra_ofs < usa_end :
ra_ofs < sizeof( RESTART_PAGE_HEADER ) ) || ra_ofs < sizeof( RESTART_PAGE_HEADER ) ) ||
ra_ofs > logfile_system_page_size) { ra_ofs > logfile_system_page_size )
{
ntfs_log_error( "$LogFile restart page specifies " ntfs_log_error( "$LogFile restart page specifies "
"inconsistent restart area offset.\n" ); "inconsistent restart area offset.\n" );
return FALSE; return FALSE;
@ -136,7 +143,8 @@ skip_usa_checks:
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
* set. * 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 " ntfs_log_error( "$LogFile restart page is not modified "
"by chkdsk but a chkdsk LSN is specified.\n" ); "by chkdsk but a chkdsk LSN is specified.\n" );
return FALSE; return FALSE;
@ -174,7 +182,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
* safe to access ra->client_array_offset. * safe to access ra->client_array_offset.
*/ */
if ( ra_ofs + offsetof( RESTART_AREA, file_size ) > if ( ra_ofs + offsetof( RESTART_AREA, file_size ) >
NTFS_BLOCK_SIZE - sizeof(u16)) { NTFS_BLOCK_SIZE - sizeof( u16 ) )
{
ntfs_log_error( "$LogFile restart area specifies " ntfs_log_error( "$LogFile restart area specifies "
"inconsistent file offset.\n" ); "inconsistent file offset.\n" );
return FALSE; return FALSE;
@ -189,7 +198,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
ca_ofs = le16_to_cpu( ra->client_array_offset ); ca_ofs = le16_to_cpu( ra->client_array_offset );
if ( ( ( ca_ofs + 7 ) & ~7 ) != ca_ofs || if ( ( ( ca_ofs + 7 ) & ~7 ) != ca_ofs ||
ra_ofs + ca_ofs > ( u16 )( NTFS_BLOCK_SIZE - ra_ofs + ca_ofs > ( u16 )( NTFS_BLOCK_SIZE -
sizeof(u16))) { sizeof( u16 ) ) )
{
ntfs_log_error( "$LogFile restart area specifies " ntfs_log_error( "$LogFile restart area specifies "
"inconsistent client array offset.\n" ); "inconsistent client array offset.\n" );
return FALSE; return FALSE;
@ -204,7 +214,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
if ( ( u32 )( ra_ofs + ra_len ) > le32_to_cpu( rp->system_page_size ) || if ( ( u32 )( ra_ofs + ra_len ) > le32_to_cpu( rp->system_page_size ) ||
( u32 )( ra_ofs + le16_to_cpu( ra->restart_area_length ) ) > ( u32 )( ra_ofs + le16_to_cpu( ra->restart_area_length ) ) >
le32_to_cpu( rp->system_page_size ) || le32_to_cpu( rp->system_page_size ) ||
ra_len > le16_to_cpu(ra->restart_area_length)) { ra_len > le16_to_cpu( ra->restart_area_length ) )
{
ntfs_log_error( "$LogFile restart area is out of bounds " ntfs_log_error( "$LogFile restart area is out of bounds "
"of the system page size specified by the " "of the system page size specified by the "
"restart page header and/or the specified " "restart page header and/or the specified "
@ -221,7 +232,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
le16_to_cpu( ra->log_clients ) ) || le16_to_cpu( ra->log_clients ) ) ||
( ra->client_in_use_list != LOGFILE_NO_CLIENT && ( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
le16_to_cpu( ra->client_in_use_list ) >= le16_to_cpu( ra->client_in_use_list ) >=
le16_to_cpu(ra->log_clients))) { le16_to_cpu( ra->log_clients ) ) )
{
ntfs_log_error( "$LogFile restart area specifies " ntfs_log_error( "$LogFile restart area specifies "
"overflowing client free and/or in use lists.\n" ); "overflowing client free and/or in use lists.\n" );
return FALSE; return FALSE;
@ -232,25 +244,29 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
*/ */
file_size = ( u64 )sle64_to_cpu( ra->file_size ); file_size = ( u64 )sle64_to_cpu( ra->file_size );
fs_bits = 0; fs_bits = 0;
while (file_size) { while ( file_size )
{
file_size >>= 1; file_size >>= 1;
fs_bits++; 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 " ntfs_log_error( "$LogFile restart area specifies "
"inconsistent sequence number bits.\n" ); "inconsistent sequence number bits.\n" );
return FALSE; return FALSE;
} }
/* The log record header length must be a multiple of 8. */ /* The log record header length must be a multiple of 8. */
if ( ( ( le16_to_cpu( ra->log_record_header_length ) + 7 ) & ~7 ) != if ( ( ( le16_to_cpu( ra->log_record_header_length ) + 7 ) & ~7 ) !=
le16_to_cpu(ra->log_record_header_length)) { le16_to_cpu( ra->log_record_header_length ) )
{
ntfs_log_error( "$LogFile restart area specifies " ntfs_log_error( "$LogFile restart area specifies "
"inconsistent log record header length.\n" ); "inconsistent log record header length.\n" );
return FALSE; return FALSE;
} }
/* Ditto for the log page data offset. */ /* Ditto for the log page data offset. */
if ( ( ( le16_to_cpu( ra->log_page_data_offset ) + 7 ) & ~7 ) != if ( ( ( le16_to_cpu( ra->log_page_data_offset ) + 7 ) & ~7 ) !=
le16_to_cpu(ra->log_page_data_offset)) { le16_to_cpu( ra->log_page_data_offset ) )
{
ntfs_log_error( "$LogFile restart area specifies " ntfs_log_error( "$LogFile restart area specifies "
"inconsistent log page data offset.\n" ); "inconsistent log page data offset.\n" );
return FALSE; return FALSE;
@ -297,20 +313,23 @@ static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
in_free_list = TRUE; in_free_list = TRUE;
check_list: check_list:
for ( idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--, for ( idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
idx = le16_to_cpu(cr->next_client)) { idx = le16_to_cpu( cr->next_client ) )
{
if ( !nr_clients || idx >= le16_to_cpu( ra->log_clients ) ) if ( !nr_clients || idx >= le16_to_cpu( ra->log_clients ) )
goto err_out; goto err_out;
/* Set @cr to the current log client record. */ /* Set @cr to the current log client record. */
cr = ca + idx; cr = ca + idx;
/* The first log client record must not have a prev_client. */ /* The first log client record must not have a prev_client. */
if (idx_is_first) { if ( idx_is_first )
{
if ( cr->prev_client != LOGFILE_NO_CLIENT ) if ( cr->prev_client != LOGFILE_NO_CLIENT )
goto err_out; goto err_out;
idx_is_first = FALSE; idx_is_first = FALSE;
} }
} }
/* Switch to and check the in use list if we just did the free list. */ /* 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; in_free_list = FALSE;
idx = le16_to_cpu( ra->client_in_use_list ); idx = le16_to_cpu( ra->client_in_use_list );
goto check_list; goto check_list;
@ -359,12 +378,14 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
ntfs_log_trace( "Entering.\n" ); ntfs_log_trace( "Entering.\n" );
/* Check the restart page header for consistency. */ /* 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. */ /* Error output already done inside the function. */
return EINVAL; return EINVAL;
} }
/* Check the restart area for consistency. */ /* 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. */ /* Error output already done inside the function. */
return EINVAL; return EINVAL;
} }
@ -385,7 +406,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
memcpy( trp, rp, le32_to_cpu( rp->system_page_size ) ); memcpy( trp, rp, le32_to_cpu( rp->system_page_size ) );
else if ( ntfs_attr_pread( log_na, pos, else if ( ntfs_attr_pread( log_na, pos,
le32_to_cpu( rp->system_page_size ), trp ) != le32_to_cpu( rp->system_page_size ), trp ) !=
le32_to_cpu(rp->system_page_size)) { le32_to_cpu( rp->system_page_size ) )
{
err = errno; err = errno;
ntfs_log_error( "Failed to read whole restart page into the " ntfs_log_error( "Failed to read whole restart page into the "
"buffer.\n" ); "buffer.\n" );
@ -399,7 +421,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
*/ */
if ( ( !ntfs_is_chkd_record( trp->magic ) || le16_to_cpu( trp->usa_count ) ) if ( ( !ntfs_is_chkd_record( trp->magic ) || le16_to_cpu( trp->usa_count ) )
&& ntfs_mst_post_read_fixup( ( NTFS_RECORD* )trp, && ntfs_mst_post_read_fixup( ( NTFS_RECORD* )trp,
le32_to_cpu(rp->system_page_size))) { le32_to_cpu( rp->system_page_size ) ) )
{
/* /*
* A multi sector tranfer error was detected. We only need to * A multi sector tranfer error was detected. We only need to
* abort if the restart page contents exceed the multi sector * abort if the restart page contents exceed the multi sector
@ -407,7 +430,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
*/ */
if ( le16_to_cpu( rp->restart_area_offset ) + if ( le16_to_cpu( rp->restart_area_offset ) +
le16_to_cpu( ra->restart_area_length ) > le16_to_cpu( ra->restart_area_length ) >
NTFS_BLOCK_SIZE - (int)sizeof(u16)) { NTFS_BLOCK_SIZE - ( int )sizeof( u16 ) )
{
ntfs_log_error( "Multi sector transfer error " ntfs_log_error( "Multi sector transfer error "
"detected in $LogFile restart page.\n" ); "detected in $LogFile restart page.\n" );
err = EINVAL; err = EINVAL;
@ -421,13 +445,16 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
*/ */
err = 0; err = 0;
if ( ntfs_is_rstr_record( rp->magic ) && if ( ntfs_is_rstr_record( rp->magic ) &&
ra->client_in_use_list != LOGFILE_NO_CLIENT) { ra->client_in_use_list != LOGFILE_NO_CLIENT )
if (!ntfs_check_log_client_array(trp)) { {
if ( !ntfs_check_log_client_array( trp ) )
{
err = EINVAL; err = EINVAL;
goto err_out; goto err_out;
} }
} }
if (lsn) { if ( lsn )
{
if ( ntfs_is_rstr_record( rp->magic ) ) if ( ntfs_is_rstr_record( rp->magic ) )
*lsn = sle64_to_cpu( ra->current_lsn ); *lsn = sle64_to_cpu( ra->current_lsn );
else /* if (ntfs_is_chkd_record(rp->magic)) */ else /* if (ntfs_is_chkd_record(rp->magic)) */
@ -436,7 +463,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
ntfs_log_trace( "Done.\n" ); ntfs_log_trace( "Done.\n" );
if ( wrp ) if ( wrp )
*wrp = trp; *wrp = trp;
else { else
{
err_out: err_out:
free( trp ); free( trp );
} }
@ -494,7 +522,8 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
* pages and the minimum number of log record pages. * pages and the minimum number of log record pages.
*/ */
if ( size < log_page_size * 2 || ( size - log_page_size * 2 ) >> if ( size < log_page_size * 2 || ( size - log_page_size * 2 ) >>
log_page_bits < MinLogRecordPages) { log_page_bits < MinLogRecordPages )
{
ntfs_log_error( "$LogFile is too small.\n" ); ntfs_log_error( "$LogFile is too small.\n" );
return FALSE; return FALSE;
} }
@ -510,12 +539,14 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
* contain empty and uninitialized records, the log file can be assumed * contain empty and uninitialized records, the log file can be assumed
* to be empty. * 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. * Read first NTFS_BLOCK_SIZE bytes of potential restart page.
*/ */
if ( ntfs_attr_pread( log_na, pos, NTFS_BLOCK_SIZE, kaddr ) != if ( ntfs_attr_pread( log_na, pos, NTFS_BLOCK_SIZE, kaddr ) !=
NTFS_BLOCK_SIZE) { NTFS_BLOCK_SIZE )
{
ntfs_log_error( "Failed to read first NTFS_BLOCK_SIZE " ntfs_log_error( "Failed to read first NTFS_BLOCK_SIZE "
"bytes of potential restart page.\n" ); "bytes of potential restart page.\n" );
goto err_out; goto err_out;
@ -538,7 +569,8 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
break; break;
/* If not a (modified by chkdsk) restart page, continue. */ /* If not a (modified by chkdsk) restart page, continue. */
if ( !ntfs_is_rstr_recordp( ( le32* )kaddr ) && if ( !ntfs_is_rstr_recordp( ( le32* )kaddr ) &&
!ntfs_is_chkd_recordp((le32*)kaddr)) { !ntfs_is_chkd_recordp( ( le32* )kaddr ) )
{
if ( !pos ) if ( !pos )
pos = NTFS_BLOCK_SIZE >> 1; pos = NTFS_BLOCK_SIZE >> 1;
continue; continue;
@ -552,12 +584,14 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
( RESTART_PAGE_HEADER* )kaddr, pos, ( RESTART_PAGE_HEADER* )kaddr, pos,
!rstr1_ph ? &rstr1_ph : &rstr2_ph, !rstr1_ph ? &rstr1_ph : &rstr2_ph,
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn ); !rstr1_ph ? &rstr1_lsn : &rstr2_lsn );
if (!err) { if ( !err )
{
/* /*
* If we have now found the first (modified by chkdsk) * If we have now found the first (modified by chkdsk)
* restart page, continue looking for the second one. * restart page, continue looking for the second one.
*/ */
if (!pos) { if ( !pos )
{
pos = NTFS_BLOCK_SIZE >> 1; pos = NTFS_BLOCK_SIZE >> 1;
continue; continue;
} }
@ -578,17 +612,20 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
if ( !pos ) if ( !pos )
pos = NTFS_BLOCK_SIZE >> 1; pos = NTFS_BLOCK_SIZE >> 1;
} }
if (kaddr) { if ( kaddr )
{
free( kaddr ); free( kaddr );
kaddr = NULL; kaddr = NULL;
} }
if (logfile_is_empty) { if ( logfile_is_empty )
{
NVolSetLogFileEmpty( vol ); NVolSetLogFileEmpty( vol );
is_empty: is_empty:
ntfs_log_trace( "Done. ($LogFile is empty.)\n" ); ntfs_log_trace( "Done. ($LogFile is empty.)\n" );
return TRUE; return TRUE;
} }
if (!rstr1_ph) { if ( !rstr1_ph )
{
if ( rstr2_ph ) if ( rstr2_ph )
ntfs_log_error( "BUG: rstr2_ph isn't NULL!\n" ); ntfs_log_error( "BUG: rstr2_ph isn't NULL!\n" );
ntfs_log_error( "Did not find any restart pages in " ntfs_log_error( "Did not find any restart pages in "
@ -596,18 +633,22 @@ is_empty:
return FALSE; return FALSE;
} }
/* If both restart pages were found, use the more recent one. */ /* 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. * If the second restart area is more recent, switch to it.
* Otherwise just throw it away. * 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 " ntfs_log_debug( "Using second restart page as it is more "
"recent.\n" ); "recent.\n" );
free( rstr1_ph ); free( rstr1_ph );
rstr1_ph = rstr2_ph; rstr1_ph = rstr2_ph;
/* rstr1_lsn = rstr2_lsn; */ /* rstr1_lsn = rstr2_lsn; */
} else { }
else
{
ntfs_log_debug( "Using first restart page as it is more " ntfs_log_debug( "Using first restart page as it is more "
"recent.\n" ); "recent.\n" );
free( rstr2_ph ); free( rstr2_ph );
@ -654,16 +695,19 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
ntfs_log_trace( "Entering.\n" ); ntfs_log_trace( "Entering.\n" );
/* An empty $LogFile must have been clean before it got emptied. */ /* 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" ); ntfs_log_trace( "$LogFile is empty\n" );
return TRUE; return TRUE;
} }
if (!rp) { if ( !rp )
{
ntfs_log_error( "Restart page header is NULL\n" ); ntfs_log_error( "Restart page header is NULL\n" );
return FALSE; return FALSE;
} }
if ( !ntfs_is_rstr_record( rp->magic ) && if ( !ntfs_is_rstr_record( rp->magic ) &&
!ntfs_is_chkd_record(rp->magic)) { !ntfs_is_chkd_record( rp->magic ) )
{
ntfs_log_error( "Restart page buffer is invalid\n" ); ntfs_log_error( "Restart page buffer is invalid\n" );
return FALSE; return FALSE;
} }
@ -675,7 +719,8 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
* we assume there was an unclean shutdown. * we assume there was an unclean shutdown.
*/ */
if ( ra->client_in_use_list != LOGFILE_NO_CLIENT && if ( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) { !( ra->flags & RESTART_VOLUME_IS_CLEAN ) )
{
ntfs_log_error( "The disk contains an unclean file system (%d, " ntfs_log_error( "The disk contains an unclean file system (%d, "
"%d).\n", le16_to_cpu( ra->client_in_use_list ), "%d).\n", le16_to_cpu( ra->client_in_use_list ),
le16_to_cpu( ra->flags ) ); le16_to_cpu( ra->flags ) );
@ -707,7 +752,8 @@ int ntfs_empty_logfile(ntfs_attr *na)
if ( NVolLogFileEmpty( na->ni->vol ) ) if ( NVolLogFileEmpty( na->ni->vol ) )
return 0; return 0;
if (!NAttrNonResident(na)) { if ( !NAttrNonResident( na ) )
{
errno = EIO; errno = EIO;
ntfs_log_perror( "Resident $LogFile $DATA attribute" ); ntfs_log_perror( "Resident $LogFile $DATA attribute" );
return -1; return -1;
@ -716,13 +762,15 @@ int ntfs_empty_logfile(ntfs_attr *na)
memset( buf, -1, NTFS_BUF_SIZE ); memset( buf, -1, NTFS_BUF_SIZE );
pos = 0; pos = 0;
while ((count = na->data_size - pos) > 0) { while ( ( count = na->data_size - pos ) > 0 )
{
if ( count > NTFS_BUF_SIZE ) if ( count > NTFS_BUF_SIZE )
count = NTFS_BUF_SIZE; count = NTFS_BUF_SIZE;
count = ntfs_attr_pwrite( na, pos, count, buf ); count = ntfs_attr_pwrite( na, pos, count, buf );
if (count <= 0) { if ( count <= 0 )
{
ntfs_log_perror( "Failed to reset $LogFile" ); ntfs_log_perror( "Failed to reset $LogFile" );
if ( count != -1 ) if ( count != -1 )
errno = EIO; errno = EIO;

View File

@ -61,10 +61,12 @@
* *
* Begins the restart area. * Begins the restart area.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*Ofs*/
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */ /* 0*/
NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h. /* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
When creating, set this to be immediately When creating, set this to be immediately
after this header structure (without any after this header structure (without any
@ -108,7 +110,8 @@ typedef struct {
* These are the so far known RESTART_AREA_* flags (16-bit) which contain * These are the so far known RESTART_AREA_* flags (16-bit) which contain
* information about the log file in which they are present. * information about the log file in which they are present.
*/ */
enum { enum
{
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16( 0x0002 ), RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16( 0x0002 ),
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */ RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
} __attribute__( ( __packed__ ) ); } __attribute__( ( __packed__ ) );
@ -122,9 +125,11 @@ typedef le16 RESTART_AREA_FLAGS;
* RESTART_PAGE_HEADER to the restart_area_offset value found in it. * RESTART_PAGE_HEADER to the restart_area_offset value found in it.
* See notes at restart_area_offset above. * See notes at restart_area_offset above.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*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. when the restart area was last written.
This happens often but what is the interval? This happens often but what is the interval?
Is it just fixed time or is it every time a Is it just fixed time or is it every time a
@ -262,9 +267,11 @@ typedef struct {
* The offset of this record is found by adding the offset of the * The offset of this record is found by adding the offset of the
* RESTART_AREA to the client_array_offset value found in it. * RESTART_AREA to the client_array_offset value found in it.
*/ */
typedef struct { typedef struct
{
/*Ofs*/ /*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. */ 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 volume, i.e. the current position within
@ -305,7 +312,8 @@ typedef struct {
* following update sequence array and then aligned to 8 byte boundary, but is * following update sequence array and then aligned to 8 byte boundary, but is
* this specified anywhere?). * this specified anywhere?).
*/ */
typedef struct { typedef struct
{
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */ NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h. u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
@ -314,15 +322,18 @@ typedef struct {
alignment). */ alignment). */
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */ u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
union { union
{
LSN last_lsn; LSN last_lsn;
s64 file_offset; s64 file_offset;
} __attribute__( ( __packed__ ) ) copy; } __attribute__( ( __packed__ ) ) copy;
u32 flags; u32 flags;
u16 page_count; u16 page_count;
u16 page_position; u16 page_position;
union { union
struct { {
struct
{
u16 next_record_offset; u16 next_record_offset;
u8 reserved[6]; u8 reserved[6];
LSN last_end_lsn; LSN last_end_lsn;
@ -335,7 +346,8 @@ typedef struct {
* *
* (Or is it log record pages?) * (Or is it log record pages?)
*/ */
typedef enum { typedef enum
{
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16( 0x0001 ), /* ??? */ LOG_RECORD_MULTI_PAGE = const_cpu_to_le16( 0x0001 ), /* ??? */
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff, LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
/* This has nothing to do with the log record. It is only so /* This has nothing to do with the log record. It is only so
@ -345,7 +357,8 @@ typedef enum {
/** /**
* struct LOG_CLIENT_ID - The log client id structure identifying a log client. * struct LOG_CLIENT_ID - The log client id structure identifying a log client.
*/ */
typedef struct { typedef struct
{
u16 seq_number; u16 seq_number;
u16 client_index; u16 client_index;
} __attribute__( ( __packed__ ) ) LOG_CLIENT_ID; } __attribute__( ( __packed__ ) ) LOG_CLIENT_ID;
@ -355,7 +368,8 @@ typedef struct {
* *
* Each log record seems to have a constant size of 0x70 bytes. * Each log record seems to have a constant size of 0x70 bytes.
*/ */
typedef struct { typedef struct
{
LSN this_lsn; LSN this_lsn;
LSN client_previous_lsn; LSN client_previous_lsn;
LSN client_undo_next_lsn; LSN client_undo_next_lsn;
@ -381,7 +395,8 @@ typedef struct {
u32 alignment_or_reserved; u32 alignment_or_reserved;
VCN target_vcn; VCN target_vcn;
/* Now at ofs 0x50. */ /* Now at ofs 0x50. */
struct { /* Only present if lcns_to_follow struct
{ /* Only present if lcns_to_follow
is not 0. */ is not 0. */
LCN lcn; LCN lcn;
} __attribute__( ( __packed__ ) ) lcn_list[0]; } __attribute__( ( __packed__ ) ) lcn_list[0];

View File

@ -67,7 +67,8 @@ static int tab;
* @flags: Flags which affect the output style * @flags: Flags which affect the output style
* @handler: Function to perform the actual logging * @handler: Function to perform the actual logging
*/ */
struct ntfs_logging { struct ntfs_logging
{
u32 levels; u32 levels;
u32 flags; u32 flags;
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE; ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
@ -77,7 +78,8 @@ struct ntfs_logging {
* ntfs_log * ntfs_log
* This struct controls all the logging within the library and tools. * This struct controls all the logging within the library and tools.
*/ */
static struct ntfs_logging ntfs_log = { static struct ntfs_logging ntfs_log =
{
#ifdef DEBUG #ifdef DEBUG
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER | NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
NTFS_LOG_LEVEL_LEAVE | NTFS_LOG_LEVEL_LEAVE |
@ -201,7 +203,8 @@ static FILE * ntfs_log_get_stream(u32 level)
{ {
FILE *stream; FILE *stream;
switch (level) { switch ( level )
{
case NTFS_LOG_LEVEL_INFO: case NTFS_LOG_LEVEL_INFO:
case NTFS_LOG_LEVEL_QUIET: case NTFS_LOG_LEVEL_QUIET:
case NTFS_LOG_LEVEL_PROGRESS: case NTFS_LOG_LEVEL_PROGRESS:
@ -237,7 +240,8 @@ static const char * ntfs_log_get_prefix(u32 level)
{ {
const char *prefix; const char *prefix;
switch (level) { switch ( level )
{
case NTFS_LOG_LEVEL_DEBUG: case NTFS_LOG_LEVEL_DEBUG:
prefix = "DEBUG: "; prefix = "DEBUG: ";
break; break;
@ -286,13 +290,15 @@ static const char * ntfs_log_get_prefix(u32 level)
*/ */
void ntfs_log_set_handler( ntfs_log_handler *handler ) void ntfs_log_set_handler( ntfs_log_handler *handler )
{ {
if (handler) { if ( handler )
{
ntfs_log.handler = handler; ntfs_log.handler = handler;
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
if ( handler == ntfs_log_handler_syslog ) if ( handler == ntfs_log_handler_syslog )
openlog( "ntfs-3g", LOG_PID, LOG_USER ); openlog( "ntfs-3g", LOG_PID, LOG_USER );
#endif #endif
} else }
else
ntfs_log.handler = ntfs_log_handler_null; ntfs_log.handler = ntfs_log_handler_null;
} }
@ -369,13 +375,15 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
return 1; return 1;
#endif #endif
ret = vsnprintf( logbuf, LOG_LINE_LEN, format, args ); ret = vsnprintf( logbuf, LOG_LINE_LEN, format, args );
if (ret < 0) { if ( ret < 0 )
{
vsyslog( LOG_NOTICE, format, args ); vsyslog( LOG_NOTICE, format, args );
ret = 1; ret = 1;
goto out; 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, ": ", LOG_LINE_LEN - ret - 1 );
strncat( logbuf, strerror( olderr ), LOG_LINE_LEN - ( ret + 3 ) ); strncat( logbuf, strerror( olderr ), LOG_LINE_LEN - ( ret + 3 ) );
ret = strlen( logbuf ); ret = strlen( logbuf );
@ -424,7 +432,8 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
stream = ( FILE* )data; stream = ( FILE* )data;
#ifdef DEBUG #ifdef DEBUG
if (level == NTFS_LOG_LEVEL_LEAVE) { if ( level == NTFS_LOG_LEVEL_LEAVE )
{
if ( tab ) if ( tab )
tab--; tab--;
return 0; return 0;
@ -593,16 +602,23 @@ int ntfs_log_handler_stderr(const char *function, const char *file,
*/ */
BOOL ntfs_log_parse_option( const char *option ) 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 ); ntfs_log_set_levels( NTFS_LOG_LEVEL_DEBUG );
return TRUE; return TRUE;
} else if (strcmp(option, "--log-verbose") == 0) { }
else if ( strcmp( option, "--log-verbose" ) == 0 )
{
ntfs_log_set_levels( NTFS_LOG_LEVEL_VERBOSE ); ntfs_log_set_levels( NTFS_LOG_LEVEL_VERBOSE );
return TRUE; return TRUE;
} else if (strcmp(option, "--log-quiet") == 0) { }
else if ( strcmp( option, "--log-quiet" ) == 0 )
{
ntfs_log_clear_levels( NTFS_LOG_LEVEL_QUIET ); ntfs_log_clear_levels( NTFS_LOG_LEVEL_QUIET );
return TRUE; return TRUE;
} else if (strcmp(option, "--log-trace") == 0) { }
else if ( strcmp( option, "--log-trace" ) == 0 )
{
ntfs_log_set_levels( NTFS_LOG_LEVEL_TRACE ); ntfs_log_set_levels( NTFS_LOG_LEVEL_TRACE );
return TRUE; return TRUE;
} }

View File

@ -24,11 +24,13 @@
#include <malloc.h> #include <malloc.h>
static inline void* ntfs_alloc (size_t size) { static inline void* ntfs_alloc ( size_t size )
{
return malloc( size ); return malloc( size );
} }
static inline void* ntfs_align (size_t size) { static inline void* ntfs_align ( size_t size )
{
#ifdef __wii__ #ifdef __wii__
return memalign( 32, size ); return memalign( 32, size );
#else #else
@ -36,7 +38,8 @@ static inline void* ntfs_align (size_t size) {
#endif #endif
} }
static inline void ntfs_free (void* mem) { static inline void ntfs_free ( void* mem )
{
free( mem ); free( mem );
} }

View File

@ -86,7 +86,8 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
ntfs_log_trace( "inode %llu\n", ( unsigned long long )MREF( mref ) ); ntfs_log_trace( "inode %llu\n", ( unsigned long long )MREF( mref ) );
if (!vol || !vol->mft_na || !b || count < 0) { if ( !vol || !vol->mft_na || !b || count < 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: b=%p count=%lld mft=%llu", __FUNCTION__, ntfs_log_perror( "%s: b=%p count=%lld mft=%llu", __FUNCTION__,
b, ( long long )count, ( unsigned long long )MREF( mref ) ); b, ( long long )count, ( unsigned long long )MREF( mref ) );
@ -95,7 +96,8 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
m = MREF( mref ); m = MREF( mref );
/* Refuse to read non-allocated mft records. */ /* Refuse to read non-allocated mft records. */
if ( m + count > vol->mft_na->initialized_size >> if ( m + count > vol->mft_na->initialized_size >>
vol->mft_record_size_bits) { vol->mft_record_size_bits )
{
errno = ESPIPE; errno = ESPIPE;
ntfs_log_perror( "Trying to read non-allocated mft records " ntfs_log_perror( "Trying to read non-allocated mft records "
"(%lld > %lld)", ( long long )m + count, "(%lld > %lld)", ( long long )m + count,
@ -105,7 +107,8 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
} }
br = ntfs_attr_mst_pread( vol->mft_na, m << vol->mft_record_size_bits, br = ntfs_attr_mst_pread( vol->mft_na, m << vol->mft_record_size_bits,
count, vol->mft_record_size, b ); count, vol->mft_record_size, b );
if (br != count) { if ( br != count )
{
if ( br != -1 ) if ( br != -1 )
errno = EIO; errno = EIO;
ntfs_log_perror( "Failed to read of MFT, mft=%llu count=%lld " ntfs_log_perror( "Failed to read of MFT, mft=%llu count=%lld "
@ -148,14 +151,16 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
void *bmirr = NULL; void *bmirr = NULL;
int cnt = 0, res = 0; int cnt = 0, res = 0;
if (!vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0) { if ( !vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0 )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
m = MREF( mref ); m = MREF( mref );
/* Refuse to write non-allocated mft records. */ /* Refuse to write non-allocated mft records. */
if ( m + count > vol->mft_na->initialized_size >> if ( m + count > vol->mft_na->initialized_size >>
vol->mft_record_size_bits) { vol->mft_record_size_bits )
{
errno = ESPIPE; errno = ESPIPE;
ntfs_log_perror( "Trying to write non-allocated mft records " ntfs_log_perror( "Trying to write non-allocated mft records "
"(%lld > %lld)", ( long long )m + count, "(%lld > %lld)", ( long long )m + count,
@ -163,8 +168,10 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
vol->mft_record_size_bits ); vol->mft_record_size_bits );
return -1; return -1;
} }
if (m < vol->mftmirr_size) { if ( m < vol->mftmirr_size )
if (!vol->mftmirr_na) { {
if ( !vol->mftmirr_na )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -178,7 +185,8 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
} }
bw = ntfs_attr_mst_pwrite( vol->mft_na, m << vol->mft_record_size_bits, bw = ntfs_attr_mst_pwrite( vol->mft_na, m << vol->mft_record_size_bits,
count, vol->mft_record_size, b ); count, vol->mft_record_size, b );
if (bw != count) { if ( bw != count )
{
if ( bw != -1 ) if ( bw != -1 )
errno = EIO; errno = EIO;
if ( bw >= 0 ) if ( bw >= 0 )
@ -188,13 +196,15 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
ntfs_log_perror( "Error writing $Mft record(s)" ); ntfs_log_perror( "Error writing $Mft record(s)" );
res = errno; res = errno;
} }
if (bmirr && bw > 0) { if ( bmirr && bw > 0 )
{
if ( bw < cnt ) if ( bw < cnt )
cnt = bw; cnt = bw;
bw = ntfs_attr_mst_pwrite( vol->mftmirr_na, bw = ntfs_attr_mst_pwrite( vol->mftmirr_na,
m << vol->mft_record_size_bits, cnt, m << vol->mft_record_size_bits, cnt,
vol->mft_record_size, bmirr ); vol->mft_record_size, bmirr );
if (bw != cnt) { if ( bw != cnt )
{
if ( bw != -1 ) if ( bw != -1 )
errno = EIO; errno = EIO;
ntfs_log_debug( "Error: failed to sync $MFTMirr! Run " ntfs_log_debug( "Error: failed to sync $MFTMirr! Run "
@ -215,13 +225,15 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
ATTR_RECORD *a; ATTR_RECORD *a;
int ret = -1; int ret = -1;
if (!ntfs_is_file_record(m->magic)) { if ( !ntfs_is_file_record( m->magic ) )
{
ntfs_log_error( "Record %llu has no FILE magic (0x%x)\n", ntfs_log_error( "Record %llu has no FILE magic (0x%x)\n",
( unsigned long long )MREF( mref ), *( le32 * )m ); ( unsigned long long )MREF( mref ), *( le32 * )m );
goto err_out; goto err_out;
} }
if (le32_to_cpu(m->bytes_allocated) != vol->mft_record_size) { if ( le32_to_cpu( m->bytes_allocated ) != vol->mft_record_size )
{
ntfs_log_error( "Record %llu has corrupt allocation size " ntfs_log_error( "Record %llu has corrupt allocation size "
"(%u <> %u)\n", ( unsigned long long )MREF( mref ), "(%u <> %u)\n", ( unsigned long long )MREF( mref ),
vol->mft_record_size, vol->mft_record_size,
@ -230,7 +242,8 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
} }
a = ( ATTR_RECORD * )( ( char * )m + le16_to_cpu( m->attrs_offset ) ); a = ( ATTR_RECORD * )( ( char * )m + le16_to_cpu( m->attrs_offset ) );
if (p2n(a) < p2n(m) || (char *)a > (char *)m + vol->mft_record_size) { if ( p2n( a ) < p2n( m ) || ( char * )a > ( char * )m + vol->mft_record_size )
{
ntfs_log_error( "Record %llu is corrupt\n", ntfs_log_error( "Record %llu is corrupt\n",
( unsigned long long )MREF( mref ) ); ( unsigned long long )MREF( mref ) );
goto err_out; goto err_out;
@ -279,14 +292,16 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
{ {
MFT_RECORD *m; MFT_RECORD *m;
if (!vol || !mrec) { if ( !vol || !mrec )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec ); ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
return -1; return -1;
} }
m = *mrec; m = *mrec;
if (!m) { if ( !m )
{
m = ntfs_malloc( vol->mft_record_size ); m = ntfs_malloc( vol->mft_record_size );
if ( !m ) if ( !m )
return -1; return -1;
@ -297,7 +312,8 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
if ( ntfs_mft_record_check( vol, mref, m ) ) if ( ntfs_mft_record_check( vol, mref, m ) )
goto err_out; goto err_out;
if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number)) { if ( MSEQNO( mref ) && MSEQNO( mref ) != le16_to_cpu( m->sequence_number ) )
{
ntfs_log_error( "Record %llu has wrong SeqNo (%d <> %d)\n", ntfs_log_error( "Record %llu has wrong SeqNo (%d <> %d)\n",
( unsigned long long )MREF( mref ), MSEQNO( mref ), ( unsigned long long )MREF( mref ), MSEQNO( mref ),
le16_to_cpu( m->sequence_number ) ); le16_to_cpu( m->sequence_number ) );
@ -332,7 +348,8 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
{ {
ATTR_RECORD *a; ATTR_RECORD *a;
if (!vol || !mrec) { if ( !vol || !mrec )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec ); ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
return -1; return -1;
@ -340,9 +357,11 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
/* Aligned to 2-byte boundary. */ /* Aligned to 2-byte boundary. */
if ( vol->major_ver < 3 || ( vol->major_ver == 3 && !vol->minor_ver ) ) if ( vol->major_ver < 3 || ( vol->major_ver == 3 && !vol->minor_ver ) )
mrec->usa_ofs = cpu_to_le16( ( sizeof( MFT_RECORD_OLD ) + 1 ) & ~1 ); mrec->usa_ofs = cpu_to_le16( ( sizeof( MFT_RECORD_OLD ) + 1 ) & ~1 );
else { else
{
/* Abort if mref is > 32 bits. */ /* Abort if mref is > 32 bits. */
if (MREF(mref) & 0x0000ffff00000000ull) { if ( MREF( mref ) & 0x0000ffff00000000ull )
{
errno = ERANGE; errno = ERANGE;
ntfs_log_perror( "Mft reference exceeds 32 bits" ); ntfs_log_perror( "Mft reference exceeds 32 bits" );
return -1; return -1;
@ -359,7 +378,8 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
if ( vol->mft_record_size >= NTFS_BLOCK_SIZE ) if ( vol->mft_record_size >= NTFS_BLOCK_SIZE )
mrec->usa_count = cpu_to_le16( vol->mft_record_size / mrec->usa_count = cpu_to_le16( vol->mft_record_size /
NTFS_BLOCK_SIZE + 1 ); NTFS_BLOCK_SIZE + 1 );
else { else
{
mrec->usa_count = cpu_to_le16( 1 ); mrec->usa_count = cpu_to_le16( 1 );
ntfs_log_error( "Sector size is bigger than MFT record size. " ntfs_log_error( "Sector size is bigger than MFT record size. "
"Setting usa_count to 1. If Windows chkdsk " "Setting usa_count to 1. If Windows chkdsk "
@ -502,16 +522,19 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
data_pos = base_ni->mft_no + 1; data_pos = base_ni->mft_no + 1;
if ( data_pos < RESERVED_MFT_RECORDS ) if ( data_pos < RESERVED_MFT_RECORDS )
data_pos = RESERVED_MFT_RECORDS; data_pos = RESERVED_MFT_RECORDS;
if (data_pos >= pass_end) { if ( data_pos >= pass_end )
{
data_pos = RESERVED_MFT_RECORDS; data_pos = RESERVED_MFT_RECORDS;
pass = 2; pass = 2;
/* This happens on a freshly formatted volume. */ /* This happens on a freshly formatted volume. */
if (data_pos >= pass_end) { if ( data_pos >= pass_end )
{
errno = ENOSPC; errno = ENOSPC;
goto leave; goto leave;
} }
} }
if (ntfs_is_mft(base_ni)) { if ( ntfs_is_mft( base_ni ) )
{
data_pos = 0; data_pos = 0;
pass = 2; pass = 2;
} }
@ -529,21 +552,24 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
b = 0; b = 0;
#endif #endif
/* Loop until a free mft record is found. */ /* Loop until a free mft record is found. */
for (; pass <= 2; size = PAGE_SIZE) { for ( ; pass <= 2; size = PAGE_SIZE )
{
/* Cap size to pass_end. */ /* Cap size to pass_end. */
ofs = data_pos >> 3; ofs = data_pos >> 3;
ll = ( ( pass_end + 7 ) >> 3 ) - ofs; ll = ( ( pass_end + 7 ) >> 3 ) - ofs;
if ( size > ll ) if ( size > ll )
size = ll; size = ll;
ll = ntfs_attr_pread( mftbmp_na, ofs, size, buf ); ll = ntfs_attr_pread( mftbmp_na, ofs, size, buf );
if (ll < 0) { if ( ll < 0 )
{
ntfs_log_perror( "Failed to read $MFT bitmap" ); ntfs_log_perror( "Failed to read $MFT bitmap" );
free( buf ); free( buf );
goto leave; goto leave;
} }
ntfs_log_debug( "Read 0x%llx bytes.\n", ( long long )ll ); ntfs_log_debug( "Read 0x%llx bytes.\n", ( long long )ll );
/* If we read at least one byte, search @buf for a zero bit. */ /* If we read at least one byte, search @buf for a zero bit. */
if (ll) { if ( ll )
{
size = ll << 3; size = ll << 3;
bit = data_pos & 7; bit = data_pos & 7;
data_pos &= ~7ull; data_pos &= ~7ull;
@ -553,7 +579,8 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
( long long )data_pos, ( long long )bit, ( long long )data_pos, ( long long )bit,
byte ? *byte : -1, b ); byte ? *byte : -1, b );
for ( ; bit < size && data_pos + bit < pass_end; for ( ; bit < size && data_pos + bit < pass_end;
bit &= ~7ull, bit += 8) { bit &= ~7ull, bit += 8 )
{
/* /*
* If we're extending $MFT and running out of the first * If we're extending $MFT and running out of the first
* mft record (base record) then give up searching since * mft record (base record) then give up searching since
@ -568,7 +595,8 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
/* Note: ffz() result must be zero based. */ /* Note: ffz() result must be zero based. */
b = ntfs_ffz( ( unsigned long ) * byte ); b = ntfs_ffz( ( unsigned long ) * byte );
if (b < 8 && b >= (bit & 7)) { if ( b < 8 && b >= ( bit & 7 ) )
{
free( buf ); free( buf );
ret = data_pos + ( bit & ~7ull ) + b; ret = data_pos + ( bit & ~7ull ) + b;
goto leave; goto leave;
@ -589,7 +617,8 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
} }
/* Do the next pass. */ /* Do the next pass. */
pass++; pass++;
if (pass == 2) { if ( pass == 2 )
{
/* /*
* Starting the second pass, in which we scan the first * Starting the second pass, in which we scan the first
* part of the zone which we omitted earlier. * part of the zone which we omitted earlier.
@ -617,8 +646,10 @@ static int ntfs_mft_attr_extend(ntfs_attr *na)
int ret = STATUS_ERROR; int ret = STATUS_ERROR;
ntfs_log_enter( "Entering\n" ); ntfs_log_enter( "Entering\n" );
if (!NInoAttrList(na->ni)) { if ( !NInoAttrList( na->ni ) )
if (ntfs_inode_add_attrlist(na->ni)) { {
if ( ntfs_inode_add_attrlist( na->ni ) )
{
ntfs_log_perror( "%s: Can not add attrlist #3", __FUNCTION__ ); ntfs_log_perror( "%s: Can not add attrlist #3", __FUNCTION__ );
goto out; goto out;
} }
@ -627,7 +658,8 @@ static int ntfs_mft_attr_extend(ntfs_attr *na)
goto out; goto out;
} }
if (ntfs_attr_update_mapping_pairs(na, 0)) { if ( ntfs_attr_update_mapping_pairs( na, 0 ) )
{
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ ); ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
goto out; goto out;
} }
@ -663,7 +695,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
*/ */
rl = ntfs_attr_find_vcn( mftbmp_na, ( mftbmp_na->allocated_size - 1 ) >> rl = ntfs_attr_find_vcn( mftbmp_na, ( mftbmp_na->allocated_size - 1 ) >>
vol->cluster_size_bits ); vol->cluster_size_bits );
if (!rl || !rl->length || rl->lcn < 0) { if ( !rl || !rl->length || rl->lcn < 0 )
{
ntfs_log_error( "Failed to determine last allocated " ntfs_log_error( "Failed to determine last allocated "
"cluster of mft bitmap attribute.\n" ); "cluster of mft bitmap attribute.\n" );
if ( rl ) if ( rl )
@ -673,13 +706,15 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
lcn = rl->lcn + rl->length; lcn = rl->lcn + rl->length;
rl2 = ntfs_cluster_alloc( vol, rl[1].vcn, 1, lcn, DATA_ZONE ); rl2 = ntfs_cluster_alloc( vol, rl[1].vcn, 1, lcn, DATA_ZONE );
if (!rl2) { if ( !rl2 )
{
ntfs_log_error( "Failed to allocate a cluster for " ntfs_log_error( "Failed to allocate a cluster for "
"the mft bitmap.\n" ); "the mft bitmap.\n" );
return STATUS_ERROR; return STATUS_ERROR;
} }
rl = ntfs_runlists_merge( mftbmp_na->rl, rl2 ); rl = ntfs_runlists_merge( mftbmp_na->rl, rl2 );
if (!rl) { if ( !rl )
{
err = errno; err = errno;
ntfs_log_error( "Failed to merge runlists for mft " ntfs_log_error( "Failed to merge runlists for mft "
"bitmap.\n" ); "bitmap.\n" );
@ -704,7 +739,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
goto undo_alloc; goto undo_alloc;
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name, if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find last attribute extent of " ntfs_log_error( "Failed to find last attribute extent of "
"mft bitmap attribute.\n" ); "mft bitmap attribute.\n" );
goto undo_alloc; goto undo_alloc;
@ -713,7 +749,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
a = ctx->attr; a = ctx->attr;
ll = sle64_to_cpu( a->lowest_vcn ); ll = sle64_to_cpu( a->lowest_vcn );
rl2 = ntfs_attr_find_vcn( mftbmp_na, ll ); rl2 = ntfs_attr_find_vcn( mftbmp_na, ll );
if (!rl2 || !rl2->length) { if ( !rl2 || !rl2->length )
{
ntfs_log_error( "Failed to determine previous last " ntfs_log_error( "Failed to determine previous last "
"allocated cluster of mft bitmap attribute.\n" ); "allocated cluster of mft bitmap attribute.\n" );
if ( rl2 ) if ( rl2 )
@ -722,7 +759,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
} }
/* Get the size for the new mapping pairs array for this extent. */ /* Get the size for the new mapping pairs array for this extent. */
mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX ); mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX );
if (mp_size <= 0) { if ( mp_size <= 0 )
{
ntfs_log_error( "Get size for mapping pairs failed for " ntfs_log_error( "Get size for mapping pairs failed for "
"mft bitmap attribute extent.\n" ); "mft bitmap attribute extent.\n" );
goto undo_alloc; goto undo_alloc;
@ -730,12 +768,14 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
/* Expand the attribute record if necessary. */ /* Expand the attribute record if necessary. */
old_alen = le32_to_cpu( a->length ); old_alen = le32_to_cpu( a->length );
if ( ntfs_attr_record_resize( m, a, mp_size + if ( ntfs_attr_record_resize( m, a, mp_size +
le16_to_cpu(a->mapping_pairs_offset))) { le16_to_cpu( a->mapping_pairs_offset ) ) )
{
ntfs_log_info( "extending $MFT bitmap\n" ); ntfs_log_info( "extending $MFT bitmap\n" );
ret = ntfs_mft_attr_extend( vol->mftbmp_na ); ret = ntfs_mft_attr_extend( vol->mftbmp_na );
if ( ret == STATUS_OK ) if ( ret == STATUS_OK )
goto ok; goto ok;
if (ret == STATUS_ERROR) { if ( ret == STATUS_ERROR )
{
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ ); ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
update_mp = TRUE; update_mp = TRUE;
} }
@ -745,7 +785,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
/* Generate the mapping pairs array directly into the attr record. */ /* Generate the mapping pairs array directly into the attr record. */
if ( ntfs_mapping_pairs_build( vol, ( u8* )a + if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
le16_to_cpu( a->mapping_pairs_offset ), mp_size, rl2, ll, le16_to_cpu( a->mapping_pairs_offset ), mp_size, rl2, ll,
NULL)) { NULL ) )
{
ntfs_log_error( "Failed to build mapping pairs array for " ntfs_log_error( "Failed to build mapping pairs array for "
"mft bitmap attribute.\n" ); "mft bitmap attribute.\n" );
errno = EIO; errno = EIO;
@ -757,7 +798,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
* We now have extended the mft bitmap allocated_size by one cluster. * We now have extended the mft bitmap allocated_size by one cluster.
* Reflect this in the ntfs_attr structure and the attribute record. * Reflect this in the ntfs_attr structure and the attribute record.
*/ */
if (a->lowest_vcn) { if ( a->lowest_vcn )
{
/* /*
* We are not in the first attribute extent, switch to it, but * We are not in the first attribute extent, switch to it, but
* first ensure the changes will make it to disk later. * first ensure the changes will make it to disk later.
@ -765,7 +807,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
ntfs_inode_mark_dirty( ctx->ntfs_ino ); ntfs_inode_mark_dirty( ctx->ntfs_ino );
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name, if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { mftbmp_na->name_len, 0, 0, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find first attribute " ntfs_log_error( "Failed to find first attribute "
"extent of mft bitmap attribute.\n" ); "extent of mft bitmap attribute.\n" );
goto restore_undo_alloc; goto restore_undo_alloc;
@ -784,7 +827,8 @@ restore_undo_alloc:
err = errno; err = errno;
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name, if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find last attribute extent of " ntfs_log_error( "Failed to find last attribute extent of "
"mft bitmap attribute.%s\n", es ); "mft bitmap attribute.%s\n", es );
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
@ -813,7 +857,8 @@ undo_alloc:
ntfs_log_error( "Failed to free cluster.%s\n", es ); ntfs_log_error( "Failed to free cluster.%s\n", es );
else else
vol->free_clusters++; vol->free_clusters++;
if (mp_rebuilt) { if ( mp_rebuilt )
{
if ( ntfs_mapping_pairs_build( vol, ( u8* )a + if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
le16_to_cpu( a->mapping_pairs_offset ), le16_to_cpu( a->mapping_pairs_offset ),
old_alen - le16_to_cpu( a->mapping_pairs_offset ), old_alen - le16_to_cpu( a->mapping_pairs_offset ),
@ -825,7 +870,8 @@ undo_alloc:
"record.%s\n", es ); "record.%s\n", es );
ntfs_inode_mark_dirty( ctx->ntfs_ino ); ntfs_inode_mark_dirty( ctx->ntfs_ino );
} }
if (update_mp) { if ( update_mp )
{
if ( ntfs_attr_update_mapping_pairs( vol->mftbmp_na, 0 ) ) if ( ntfs_attr_update_mapping_pairs( vol->mftbmp_na, 0 ) )
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ ); ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
} }
@ -884,7 +930,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
goto out; goto out;
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name, if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { mftbmp_na->name_len, 0, 0, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find first attribute extent of " ntfs_log_error( "Failed to find first attribute extent of "
"mft bitmap attribute.\n" ); "mft bitmap attribute.\n" );
err = errno; err = errno;
@ -895,7 +942,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
old_initialized_size = mftbmp_na->initialized_size; old_initialized_size = mftbmp_na->initialized_size;
mftbmp_na->initialized_size += 8; mftbmp_na->initialized_size += 8;
a->initialized_size = cpu_to_sle64( mftbmp_na->initialized_size ); a->initialized_size = cpu_to_sle64( mftbmp_na->initialized_size );
if (mftbmp_na->initialized_size > mftbmp_na->data_size) { if ( mftbmp_na->initialized_size > mftbmp_na->data_size )
{
mftbmp_na->data_size = mftbmp_na->initialized_size; mftbmp_na->data_size = mftbmp_na->initialized_size;
a->data_size = cpu_to_sle64( mftbmp_na->data_size ); a->data_size = cpu_to_sle64( mftbmp_na->data_size );
} }
@ -905,7 +953,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
/* Initialize the mft bitmap attribute value with zeroes. */ /* Initialize the mft bitmap attribute value with zeroes. */
ll = 0; ll = 0;
ll = ntfs_attr_pwrite( mftbmp_na, old_initialized_size, 8, &ll ); ll = ntfs_attr_pwrite( mftbmp_na, old_initialized_size, 8, &ll );
if (ll == 8) { if ( ll == 8 )
{
ntfs_log_debug( "Wrote eight initialized bytes to mft bitmap.\n" ); ntfs_log_debug( "Wrote eight initialized bytes to mft bitmap.\n" );
vol->free_mft_records += ( 8 * 8 ); vol->free_mft_records += ( 8 * 8 );
ret = 0; ret = 0;
@ -921,7 +970,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
goto err_out; goto err_out;
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name, if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { mftbmp_na->name_len, 0, 0, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find first attribute extent of " ntfs_log_error( "Failed to find first attribute extent of "
"mft bitmap attribute.%s\n", es ); "mft bitmap attribute.%s\n", es );
put_err_out: put_err_out:
@ -931,7 +981,8 @@ put_err_out:
a = ctx->attr; a = ctx->attr;
mftbmp_na->initialized_size = old_initialized_size; mftbmp_na->initialized_size = old_initialized_size;
a->initialized_size = cpu_to_sle64( old_initialized_size ); a->initialized_size = cpu_to_sle64( old_initialized_size );
if (mftbmp_na->data_size != old_data_size) { if ( mftbmp_na->data_size != old_data_size )
{
mftbmp_na->data_size = old_data_size; mftbmp_na->data_size = old_data_size;
a->data_size = cpu_to_sle64( old_data_size ); a->data_size = cpu_to_sle64( old_data_size );
} }
@ -989,7 +1040,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
rl = ntfs_attr_find_vcn( mft_na, rl = ntfs_attr_find_vcn( mft_na,
( mft_na->allocated_size - 1 ) >> vol->cluster_size_bits ); ( mft_na->allocated_size - 1 ) >> vol->cluster_size_bits );
if (!rl || !rl->length || rl->lcn < 0) { if ( !rl || !rl->length || rl->lcn < 0 )
{
ntfs_log_error( "Failed to determine last allocated " ntfs_log_error( "Failed to determine last allocated "
"cluster of mft data attribute.\n" ); "cluster of mft data attribute.\n" );
if ( rl ) if ( rl )
@ -1009,11 +1061,13 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
nr = min_nr; nr = min_nr;
old_last_vcn = rl[1].vcn; old_last_vcn = rl[1].vcn;
do { do
{
rl2 = ntfs_cluster_alloc( vol, old_last_vcn, nr, lcn, MFT_ZONE ); rl2 = ntfs_cluster_alloc( vol, old_last_vcn, nr, lcn, MFT_ZONE );
if ( rl2 ) if ( rl2 )
break; break;
if (errno != ENOSPC || nr == min_nr) { if ( errno != ENOSPC || nr == min_nr )
{
ntfs_log_perror( "Failed to allocate (%lld) clusters " ntfs_log_perror( "Failed to allocate (%lld) clusters "
"for $MFT", ( long long )nr ); "for $MFT", ( long long )nr );
goto out; goto out;
@ -1026,12 +1080,14 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
nr = min_nr; nr = min_nr;
ntfs_log_debug( "Retrying mft data allocation with minimal cluster " ntfs_log_debug( "Retrying mft data allocation with minimal cluster "
"count %lli.\n", ( long long )nr ); "count %lli.\n", ( long long )nr );
} while (1); }
while ( 1 );
ntfs_log_debug( "Allocated %lld clusters.\n", ( long long )nr ); ntfs_log_debug( "Allocated %lld clusters.\n", ( long long )nr );
rl = ntfs_runlists_merge( mft_na->rl, rl2 ); rl = ntfs_runlists_merge( mft_na->rl, rl2 );
if (!rl) { if ( !rl )
{
err = errno; err = errno;
ntfs_log_error( "Failed to merge runlists for mft data " ntfs_log_error( "Failed to merge runlists for mft data "
"attribute.\n" ); "attribute.\n" );
@ -1053,7 +1109,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
goto undo_alloc; goto undo_alloc;
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0, if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
rl[1].vcn, NULL, 0, ctx)) { rl[1].vcn, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find last attribute extent of " ntfs_log_error( "Failed to find last attribute extent of "
"mft data attribute.\n" ); "mft data attribute.\n" );
goto undo_alloc; goto undo_alloc;
@ -1062,7 +1119,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
a = ctx->attr; a = ctx->attr;
ll = sle64_to_cpu( a->lowest_vcn ); ll = sle64_to_cpu( a->lowest_vcn );
rl2 = ntfs_attr_find_vcn( mft_na, ll ); rl2 = ntfs_attr_find_vcn( mft_na, ll );
if (!rl2 || !rl2->length) { if ( !rl2 || !rl2->length )
{
ntfs_log_error( "Failed to determine previous last " ntfs_log_error( "Failed to determine previous last "
"allocated cluster of mft data attribute.\n" ); "allocated cluster of mft data attribute.\n" );
if ( rl2 ) if ( rl2 )
@ -1071,7 +1129,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
} }
/* Get the size for the new mapping pairs array for this extent. */ /* Get the size for the new mapping pairs array for this extent. */
mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX ); mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX );
if (mp_size <= 0) { if ( mp_size <= 0 )
{
ntfs_log_error( "Get size for mapping pairs failed for " ntfs_log_error( "Get size for mapping pairs failed for "
"mft data attribute extent.\n" ); "mft data attribute extent.\n" );
goto undo_alloc; goto undo_alloc;
@ -1079,11 +1138,13 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
/* Expand the attribute record if necessary. */ /* Expand the attribute record if necessary. */
old_alen = le32_to_cpu( a->length ); old_alen = le32_to_cpu( a->length );
if ( ntfs_attr_record_resize( m, a, if ( ntfs_attr_record_resize( m, a,
mp_size + le16_to_cpu(a->mapping_pairs_offset))) { mp_size + le16_to_cpu( a->mapping_pairs_offset ) ) )
{
ret = ntfs_mft_attr_extend( vol->mft_na ); ret = ntfs_mft_attr_extend( vol->mft_na );
if ( ret == STATUS_OK ) if ( ret == STATUS_OK )
goto ok; goto ok;
if (ret == STATUS_ERROR) { if ( ret == STATUS_ERROR )
{
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ ); ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
update_mp = TRUE; update_mp = TRUE;
} }
@ -1095,7 +1156,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
*/ */
if ( ntfs_mapping_pairs_build( vol, if ( ntfs_mapping_pairs_build( vol,
( u8* )a + le16_to_cpu( a->mapping_pairs_offset ), mp_size, ( u8* )a + le16_to_cpu( a->mapping_pairs_offset ), mp_size,
rl2, ll, NULL)) { rl2, ll, NULL ) )
{
ntfs_log_error( "Failed to build mapping pairs array of " ntfs_log_error( "Failed to build mapping pairs array of "
"mft data attribute.\n" ); "mft data attribute.\n" );
errno = EIO; errno = EIO;
@ -1109,7 +1171,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
* @rl is the last (non-terminator) runlist element of mft data * @rl is the last (non-terminator) runlist element of mft data
* attribute. * attribute.
*/ */
if (a->lowest_vcn) { if ( a->lowest_vcn )
{
/* /*
* We are not in the first attribute extent, switch to it, but * We are not in the first attribute extent, switch to it, but
* first ensure the changes will make it to disk later. * first ensure the changes will make it to disk later.
@ -1117,7 +1180,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
ntfs_inode_mark_dirty( ctx->ntfs_ino ); ntfs_inode_mark_dirty( ctx->ntfs_ino );
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, if ( ntfs_attr_lookup( mft_na->type, mft_na->name,
mft_na->name_len, 0, 0, NULL, 0, ctx)) { mft_na->name_len, 0, 0, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find first attribute " ntfs_log_error( "Failed to find first attribute "
"extent of mft data attribute.\n" ); "extent of mft data attribute.\n" );
goto restore_undo_alloc; goto restore_undo_alloc;
@ -1139,7 +1203,8 @@ restore_undo_alloc:
err = errno; err = errno;
ntfs_attr_reinit_search_ctx( ctx ); ntfs_attr_reinit_search_ctx( ctx );
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0, if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
rl[1].vcn, NULL, 0, ctx)) { rl[1].vcn, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find last attribute extent of " ntfs_log_error( "Failed to find last attribute extent of "
"mft data attribute.%s\n", es ); "mft data attribute.%s\n", es );
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
@ -1164,7 +1229,8 @@ undo_alloc:
if ( ntfs_rl_truncate( &mft_na->rl, old_last_vcn ) ) if ( ntfs_rl_truncate( &mft_na->rl, old_last_vcn ) )
ntfs_log_error( "Failed to truncate mft data attribute " ntfs_log_error( "Failed to truncate mft data attribute "
"runlist.%s\n", es ); "runlist.%s\n", es );
if (mp_rebuilt) { if ( mp_rebuilt )
{
if ( ntfs_mapping_pairs_build( vol, ( u8* )a + if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
le16_to_cpu( a->mapping_pairs_offset ), le16_to_cpu( a->mapping_pairs_offset ),
old_alen - le16_to_cpu( a->mapping_pairs_offset ), old_alen - le16_to_cpu( a->mapping_pairs_offset ),
@ -1176,7 +1242,8 @@ undo_alloc:
"record.%s\n", es ); "record.%s\n", es );
ntfs_inode_mark_dirty( ctx->ntfs_ino ); ntfs_inode_mark_dirty( ctx->ntfs_ino );
} }
if (update_mp) { if ( update_mp )
{
if ( ntfs_attr_update_mapping_pairs( vol->mft_na, 0 ) ) if ( ntfs_attr_update_mapping_pairs( vol->mft_na, 0 ) )
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ ); ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
} }
@ -1213,7 +1280,8 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
( long long )mft_na->allocated_size, ( long long )mft_na->allocated_size,
( long long )mft_na->data_size, ( long long )mft_na->data_size,
( long long )mft_na->initialized_size ); ( long long )mft_na->initialized_size );
while (size > mft_na->allocated_size) { while ( size > mft_na->allocated_size )
{
if ( ntfs_mft_data_extend_allocation( vol ) == STATUS_ERROR ) if ( ntfs_mft_data_extend_allocation( vol ) == STATUS_ERROR )
goto out; goto out;
ntfs_log_debug( "Status of mft data after allocation extension: " ntfs_log_debug( "Status of mft data after allocation extension: "
@ -1234,13 +1302,15 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
* needed by ntfs_mft_record_format(). We will update the attribute * needed by ntfs_mft_record_format(). We will update the attribute
* record itself in one fell swoop later on. * record itself in one fell swoop later on.
*/ */
while (size > mft_na->initialized_size) { while ( size > mft_na->initialized_size )
{
s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits; s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
mft_na->initialized_size += vol->mft_record_size; mft_na->initialized_size += vol->mft_record_size;
if ( mft_na->initialized_size > mft_na->data_size ) if ( mft_na->initialized_size > mft_na->data_size )
mft_na->data_size = mft_na->initialized_size; mft_na->data_size = mft_na->initialized_size;
ntfs_log_debug( "Initializing mft record 0x%llx.\n", ( long long )ll2 ); ntfs_log_debug( "Initializing mft record 0x%llx.\n", ( long long )ll2 );
if (ntfs_mft_record_format(vol, ll2) < 0) { if ( ntfs_mft_record_format( vol, ll2 ) < 0 )
{
ntfs_log_perror( "Failed to format mft record" ); ntfs_log_perror( "Failed to format mft record" );
goto undo_data_init; goto undo_data_init;
} }
@ -1252,7 +1322,8 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
goto undo_data_init; goto undo_data_init;
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0, if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
0, NULL, 0, ctx)) { 0, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find first attribute extent of " ntfs_log_error( "Failed to find first attribute extent of "
"mft data attribute.\n" ); "mft data attribute.\n" );
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
@ -1304,7 +1375,8 @@ static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size)
mft_na = vol->mft_na; mft_na = vol->mft_na;
mftbmp_na = vol->mftbmp_na; mftbmp_na = vol->mftbmp_na;
if (size > mft_na->allocated_size || size > mft_na->initialized_size) { if ( size > mft_na->allocated_size || size > mft_na->initialized_size )
{
errno = EIO; errno = EIO;
ntfs_log_perror( "%s: unexpected $MFT sizes, see below", __FUNCTION__ ); ntfs_log_perror( "%s: unexpected $MFT sizes, see below", __FUNCTION__ );
ntfs_log_error( "$MFT: size=%lld allocated_size=%lld " ntfs_log_error( "$MFT: size=%lld allocated_size=%lld "
@ -1325,7 +1397,8 @@ static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size)
goto undo_data_init; goto undo_data_init;
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0, if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
0, NULL, 0, ctx)) { 0, NULL, 0, ctx ) )
{
ntfs_log_error( "Failed to find first attribute extent of " ntfs_log_error( "Failed to find first attribute extent of "
"mft data attribute.\n" ); "mft data attribute.\n" );
ntfs_attr_put_search_ctx( ctx ); ntfs_attr_put_search_ctx( ctx );
@ -1384,7 +1457,8 @@ static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
goto err_out; goto err_out;
found_free_rec: found_free_rec:
if (ntfs_bitmap_set_bit(mftbmp_na, bit)) { if ( ntfs_bitmap_set_bit( mftbmp_na, bit ) )
{
ntfs_log_error( "Failed to allocate bit in mft bitmap #2\n" ); ntfs_log_error( "Failed to allocate bit in mft bitmap #2\n" );
goto err_out; goto err_out;
} }
@ -1403,12 +1477,14 @@ found_free_rec:
if ( !m ) if ( !m )
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
if (ntfs_mft_record_read(vol, bit, m)) { if ( ntfs_mft_record_read( vol, bit, m ) )
{
free( m ); free( m );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
} }
/* Sanity check that the mft record is really not in use. */ /* Sanity check that the mft record is really not in use. */
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) { if ( ntfs_is_file_record( m->magic ) && ( m->flags & MFT_RECORD_IN_USE ) )
{
ntfs_log_error( "Inode %lld is used but it wasn't marked in " ntfs_log_error( "Inode %lld is used but it wasn't marked in "
"$MFT bitmap. Fixed.\n", ( long long )bit ); "$MFT bitmap. Fixed.\n", ( long long )bit );
free( m ); free( m );
@ -1417,7 +1493,8 @@ found_free_rec:
seq_no = m->sequence_number; seq_no = m->sequence_number;
usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) ); usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) );
if (ntfs_mft_record_layout(vol, bit, m)) { if ( ntfs_mft_record_layout( vol, bit, m ) )
{
ntfs_log_error( "Failed to re-format mft record.\n" ); ntfs_log_error( "Failed to re-format mft record.\n" );
free( m ); free( m );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
@ -1431,7 +1508,8 @@ found_free_rec:
m->flags |= MFT_RECORD_IN_USE; m->flags |= MFT_RECORD_IN_USE;
/* Now need to open an ntfs inode for the mft record. */ /* Now need to open an ntfs inode for the mft record. */
ni = ntfs_inode_allocate( vol ); ni = ntfs_inode_allocate( vol );
if (!ni) { if ( !ni )
{
ntfs_log_error( "Failed to allocate buffer for inode.\n" ); ntfs_log_error( "Failed to allocate buffer for inode.\n" );
free( m ); free( m );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
@ -1451,18 +1529,21 @@ found_free_rec:
* Attach the extent inode to the base inode, reallocating * Attach the extent inode to the base inode, reallocating
* memory if needed. * memory if needed.
*/ */
if (!(base_ni->nr_extents & 3)) { if ( !( base_ni->nr_extents & 3 ) )
{
ntfs_inode **extent_nis; ntfs_inode **extent_nis;
int i; int i;
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * ); i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
extent_nis = ntfs_malloc( i ); extent_nis = ntfs_malloc( i );
if (!extent_nis) { if ( !extent_nis )
{
free( m ); free( m );
free( ni ); free( ni );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
} }
if (base_ni->nr_extents) { if ( base_ni->nr_extents )
{
memcpy( extent_nis, base_ni->extent_nis, memcpy( extent_nis, base_ni->extent_nis,
i - 4 * sizeof( ntfs_inode * ) ); i - 4 * sizeof( ntfs_inode * ) );
free( base_ni->extent_nis ); free( base_ni->extent_nis );
@ -1599,12 +1680,14 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
( long long )base_ni->mft_no ); ( long long )base_ni->mft_no );
else else
ntfs_log_enter( "Entering (allocating a base mft record)\n" ); ntfs_log_enter( "Entering (allocating a base mft record)\n" );
if (!vol || !vol->mft_na || !vol->mftbmp_na) { if ( !vol || !vol->mft_na || !vol->mftbmp_na )
{
errno = EINVAL; errno = EINVAL;
goto out; goto out;
} }
if (ntfs_is_mft(base_ni)) { if ( ntfs_is_mft( base_ni ) )
{
ni = ntfs_mft_rec_alloc( vol ); ni = ntfs_mft_rec_alloc( vol );
goto out; goto out;
} }
@ -1613,7 +1696,8 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
mftbmp_na = vol->mftbmp_na; mftbmp_na = vol->mftbmp_na;
retry: retry:
bit = ntfs_mft_bitmap_find_free_rec( vol, base_ni ); bit = ntfs_mft_bitmap_find_free_rec( vol, base_ni );
if (bit >= 0) { if ( bit >= 0 )
{
ntfs_log_debug( "found free record (#1) at %lld\n", ntfs_log_debug( "found free record (#1) at %lld\n",
( long long )bit ); ( long long )bit );
goto found_free_rec; goto found_free_rec;
@ -1630,7 +1714,8 @@ retry:
*/ */
ll = mft_na->initialized_size >> vol->mft_record_size_bits; ll = mft_na->initialized_size >> vol->mft_record_size_bits;
if ( mftbmp_na->initialized_size << 3 > ll && if ( mftbmp_na->initialized_size << 3 > ll &&
mftbmp_na->initialized_size > RESERVED_MFT_RECORDS / 8) { mftbmp_na->initialized_size > RESERVED_MFT_RECORDS / 8 )
{
bit = ll; bit = ll;
if ( bit < RESERVED_MFT_RECORDS ) if ( bit < RESERVED_MFT_RECORDS )
bit = RESERVED_MFT_RECORDS; bit = RESERVED_MFT_RECORDS;
@ -1648,13 +1733,15 @@ retry:
( long long )mftbmp_na->allocated_size, ( long long )mftbmp_na->allocated_size,
( long long )mftbmp_na->data_size, ( long long )mftbmp_na->data_size,
( long long )mftbmp_na->initialized_size ); ( long long )mftbmp_na->initialized_size );
if (mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size) { if ( mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size )
{
int ret = ntfs_mft_bitmap_extend_allocation( vol ); int ret = ntfs_mft_bitmap_extend_allocation( vol );
if ( ret == STATUS_ERROR ) if ( ret == STATUS_ERROR )
goto err_out; goto err_out;
if (ret == STATUS_KEEP_SEARCHING) { if ( ret == STATUS_KEEP_SEARCHING )
{
ret = ntfs_mft_bitmap_extend_allocation( vol ); ret = ntfs_mft_bitmap_extend_allocation( vol );
if ( ret != STATUS_OK ) if ( ret != STATUS_OK )
goto err_out; goto err_out;
@ -1684,7 +1771,8 @@ retry:
ntfs_log_debug( "found free record (#3) at %lld\n", ( long long )bit ); ntfs_log_debug( "found free record (#3) at %lld\n", ( long long )bit );
found_free_rec: found_free_rec:
/* @bit is the found free mft record, allocate it in the mft bitmap. */ /* @bit is the found free mft record, allocate it in the mft bitmap. */
if (ntfs_bitmap_set_bit(mftbmp_na, bit)) { if ( ntfs_bitmap_set_bit( mftbmp_na, bit ) )
{
ntfs_log_error( "Failed to allocate bit in mft bitmap.\n" ); ntfs_log_error( "Failed to allocate bit in mft bitmap.\n" );
goto err_out; goto err_out;
} }
@ -1705,12 +1793,14 @@ found_free_rec:
if ( !m ) if ( !m )
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
if (ntfs_mft_record_read(vol, bit, m)) { if ( ntfs_mft_record_read( vol, bit, m ) )
{
free( m ); free( m );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
} }
/* Sanity check that the mft record is really not in use. */ /* Sanity check that the mft record is really not in use. */
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) { if ( ntfs_is_file_record( m->magic ) && ( m->flags & MFT_RECORD_IN_USE ) )
{
ntfs_log_error( "Inode %lld is used but it wasn't marked in " ntfs_log_error( "Inode %lld is used but it wasn't marked in "
"$MFT bitmap. Fixed.\n", ( long long )bit ); "$MFT bitmap. Fixed.\n", ( long long )bit );
free( m ); free( m );
@ -1718,7 +1808,8 @@ found_free_rec:
} }
seq_no = m->sequence_number; seq_no = m->sequence_number;
usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) ); usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) );
if (ntfs_mft_record_layout(vol, bit, m)) { if ( ntfs_mft_record_layout( vol, bit, m ) )
{
ntfs_log_error( "Failed to re-format mft record.\n" ); ntfs_log_error( "Failed to re-format mft record.\n" );
free( m ); free( m );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
@ -1732,7 +1823,8 @@ found_free_rec:
m->flags |= MFT_RECORD_IN_USE; m->flags |= MFT_RECORD_IN_USE;
/* Now need to open an ntfs inode for the mft record. */ /* Now need to open an ntfs inode for the mft record. */
ni = ntfs_inode_allocate( vol ); ni = ntfs_inode_allocate( vol );
if (!ni) { if ( !ni )
{
ntfs_log_error( "Failed to allocate buffer for inode.\n" ); ntfs_log_error( "Failed to allocate buffer for inode.\n" );
free( m ); free( m );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
@ -1744,7 +1836,8 @@ found_free_rec:
* extent inode and attach it to the base inode. Also, set the base * extent inode and attach it to the base inode. Also, set the base
* mft record reference in the extent inode. * mft record reference in the extent inode.
*/ */
if (base_ni) { if ( base_ni )
{
ni->nr_extents = -1; ni->nr_extents = -1;
ni->base_ni = base_ni; ni->base_ni = base_ni;
m->base_mft_record = MK_LE_MREF( base_ni->mft_no, m->base_mft_record = MK_LE_MREF( base_ni->mft_no,
@ -1753,18 +1846,21 @@ found_free_rec:
* Attach the extent inode to the base inode, reallocating * Attach the extent inode to the base inode, reallocating
* memory if needed. * memory if needed.
*/ */
if (!(base_ni->nr_extents & 3)) { if ( !( base_ni->nr_extents & 3 ) )
{
ntfs_inode **extent_nis; ntfs_inode **extent_nis;
int i; int i;
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * ); i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
extent_nis = ntfs_malloc( i ); extent_nis = ntfs_malloc( i );
if (!extent_nis) { if ( !extent_nis )
{
free( m ); free( m );
free( ni ); free( ni );
goto undo_mftbmp_alloc; goto undo_mftbmp_alloc;
} }
if (base_ni->nr_extents) { if ( base_ni->nr_extents )
{
memcpy( extent_nis, base_ni->extent_nis, memcpy( extent_nis, base_ni->extent_nis,
i - 4 * sizeof( ntfs_inode * ) ); i - 4 * sizeof( ntfs_inode * ) );
free( base_ni->extent_nis ); free( base_ni->extent_nis );
@ -1824,7 +1920,8 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no ); ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
if (!vol || !vol->mftbmp_na || !ni) { if ( !vol || !vol->mftbmp_na || !ni )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -1846,13 +1943,15 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
/* Set the inode dirty and write it out. */ /* Set the inode dirty and write it out. */
ntfs_inode_mark_dirty( ni ); ntfs_inode_mark_dirty( ni );
if (ntfs_inode_sync(ni)) { if ( ntfs_inode_sync( ni ) )
{
err = errno; err = errno;
goto sync_rollback; goto sync_rollback;
} }
/* Clear the bit in the $MFT/$BITMAP corresponding to this record. */ /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
if (ntfs_bitmap_clear_bit(vol->mftbmp_na, mft_no)) { if ( ntfs_bitmap_clear_bit( vol->mftbmp_na, mft_no ) )
{
err = errno; err = errno;
// FIXME: If ntfs_bitmap_clear_run() guarantees rollback on // FIXME: If ntfs_bitmap_clear_run() guarantees rollback on
// error, this could be changed to goto sync_rollback; // error, this could be changed to goto sync_rollback;
@ -1861,9 +1960,11 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
/* Throw away the now freed inode. */ /* Throw away the now freed inode. */
#if CACHE_NIDATA_SIZE #if CACHE_NIDATA_SIZE
if (!ntfs_inode_real_close(ni)) { if ( !ntfs_inode_real_close( ni ) )
{
#else #else
if (!ntfs_inode_close(ni)) { if ( !ntfs_inode_close( ni ) )
{
#endif #endif
vol->free_mft_records++; vol->free_mft_records++;
return 0; return 0;
@ -1894,7 +1995,8 @@ int ntfs_mft_usn_dec(MFT_RECORD *mrec)
u16 usn; u16 usn;
le16 *usnp; le16 *usnp;
if (!mrec) { if ( !mrec )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }

View File

@ -61,7 +61,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
/* Size and alignment checks. */ /* Size and alignment checks. */
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 || if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size || ( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { ( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: magic: 0x%08x size: %d usa_ofs: %d " ntfs_log_perror( "%s: magic: 0x%08x size: %d usa_ofs: %d "
"usa_count: %d", __FUNCTION__, *( le32 * )b, "usa_count: %d", __FUNCTION__, *( le32 * )b,
@ -85,8 +86,10 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
/* /*
* Check for incomplete multi sector transfer(s). * Check for incomplete multi sector transfer(s).
*/ */
while (usa_count--) { while ( usa_count-- )
if (*data_pos != usn) { {
if ( *data_pos != usn )
{
/* /*
* Incomplete multi sector transfer detected! )-: * Incomplete multi sector transfer detected! )-:
* Set the magic to "BAAD" and return failure. * Set the magic to "BAAD" and return failure.
@ -106,7 +109,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
usa_count = le16_to_cpu( b->usa_count ) - 1; usa_count = le16_to_cpu( b->usa_count ) - 1;
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1; data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
/* Fixup all sectors. */ /* Fixup all sectors. */
while (usa_count--) { while ( usa_count-- )
{
/* /*
* Increment position in usa and restore original data from * Increment position in usa and restore original data from
* the usa into the data buffer. * the usa into the data buffer.
@ -147,7 +151,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
/* Sanity check + only fixup if it makes sense. */ /* Sanity check + only fixup if it makes sense. */
if ( !b || ntfs_is_baad_record( b->magic ) || if ( !b || ntfs_is_baad_record( b->magic ) ||
ntfs_is_hole_record(b->magic)) { ntfs_is_hole_record( b->magic ) )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: bad argument", __FUNCTION__ ); ntfs_log_perror( "%s: bad argument", __FUNCTION__ );
return -1; return -1;
@ -159,7 +164,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
/* Size and alignment checks. */ /* Size and alignment checks. */
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 || if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size || ( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { ( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s", __FUNCTION__ ); ntfs_log_perror( "%s", __FUNCTION__ );
return -1; return -1;
@ -178,7 +184,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
/* Position in data of first u16 that needs fixing up. */ /* Position in data of first u16 that needs fixing up. */
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1; data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
/* Fixup all sectors. */ /* Fixup all sectors. */
while (usa_count--) { while ( usa_count-- )
{
/* /*
* Increment the position in the usa and save the * Increment the position in the usa and save the
* original data from the data buffer into the usa. * original data from the data buffer into the usa.
@ -217,7 +224,8 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1; data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
/* Fixup all sectors. */ /* Fixup all sectors. */
while (usa_count--) { while ( usa_count-- )
{
/* /*
* Increment position in usa and restore original data from * Increment position in usa and restore original data from
* the usa into the data buffer. * the usa into the data buffer.

View File

@ -41,7 +41,8 @@
#include "cache.h" #include "cache.h"
// NTFS device driver devoptab // NTFS device driver devoptab
static const devoptab_t devops_ntfs = { static const devoptab_t devops_ntfs =
{
NULL, /* Device name */ NULL, /* Device name */
sizeof ( ntfs_file_state ), sizeof ( ntfs_file_state ),
ntfs_open_r, ntfs_open_r,
@ -72,7 +73,8 @@ void ntfsInit (void)
static bool isInit = false; static bool isInit = false;
// Initialise ntfs-3g (if not already done so) // Initialise ntfs-3g (if not already done so)
if (!isInit) { if ( !isInit )
{
isInit = true; isInit = true;
// Set the log handler // Set the log handler
@ -98,7 +100,8 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
sec_t part_lba = 0; sec_t part_lba = 0;
int i; int i;
union { union
{
u8 buffer[512]; u8 buffer[512];
MASTER_BOOT_RECORD mbr; MASTER_BOOT_RECORD mbr;
EXTENDED_BOOT_RECORD ebr; EXTENDED_BOOT_RECORD ebr;
@ -106,7 +109,8 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
} sector; } sector;
// Sanity check // Sanity check
if (!interface) { if ( !interface )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -117,27 +121,32 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
ntfsInit(); ntfsInit();
// Start the device and check that it is inserted // Start the device and check that it is inserted
if (!interface->startup()) { if ( !interface->startup() )
{
errno = EIO; errno = EIO;
return -1; return -1;
} }
if (!interface->isInserted()) { if ( !interface->isInserted() )
{
return 0; return 0;
} }
// Read the first sector on the device // Read the first sector on the device
if (!interface->readSectors(0, 1, &sector.buffer)) { if ( !interface->readSectors( 0, 1, &sector.buffer ) )
{
errno = EIO; errno = EIO;
return -1; return -1;
} }
// If this is the devices master boot record // If this is the devices master boot record
if (sector.mbr.signature == MBR_SIGNATURE) { if ( sector.mbr.signature == MBR_SIGNATURE )
{
memcpy( &mbr, &sector, sizeof( MASTER_BOOT_RECORD ) ); memcpy( &mbr, &sector, sizeof( MASTER_BOOT_RECORD ) );
ntfs_log_debug( "Valid Master Boot Record found\n" ); ntfs_log_debug( "Valid Master Boot Record found\n" );
// Search the partition table for all NTFS partitions (max. 4 primary partitions) // 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]; partition = &mbr.partitions[i];
part_lba = le32_to_cpu( mbr.partitions[i].lba_start ); part_lba = le32_to_cpu( mbr.partitions[i].lba_start );
@ -146,25 +155,32 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
part_lba, partition->type ); part_lba, partition->type );
// Figure out what type of partition this is // Figure out what type of partition this is
switch (partition->type) { switch ( partition->type )
{
// Ignore empty partitions // Ignore empty partitions
case PARTITION_TYPE_EMPTY: case PARTITION_TYPE_EMPTY:
continue; continue;
// NTFS partition // NTFS partition
case PARTITION_TYPE_NTFS: { case PARTITION_TYPE_NTFS:
{
ntfs_log_debug( "Partition %i: Claims to be NTFS\n", i + 1 ); ntfs_log_debug( "Partition %i: Claims to be NTFS\n", i + 1 );
// Read and validate the NTFS partition // Read and validate the NTFS partition
if (interface->readSectors(part_lba, 1, &sector)) { if ( interface->readSectors( part_lba, 1, &sector ) )
if (sector.boot.oem_id == NTFS_OEM_ID) { {
if ( sector.boot.oem_id == NTFS_OEM_ID )
{
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 ); 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_starts[partition_count] = part_lba;
partition_count++; partition_count++;
} }
} else { }
else
{
ntfs_log_debug( "Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1 ); ntfs_log_debug( "Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1 );
} }
} }
@ -175,17 +191,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
// DOS 3.3+ or Windows 95 extended partition // DOS 3.3+ or Windows 95 extended partition
case PARTITION_TYPE_DOS33_EXTENDED: 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 ); ntfs_log_debug( "Partition %i: Claims to be Extended\n", i + 1 );
// Walk the extended partition chain, finding all NTFS partitions within it // Walk the extended partition chain, finding all NTFS partitions within it
sec_t ebr_lba = part_lba; sec_t ebr_lba = part_lba;
sec_t next_erb_lba = 0; sec_t next_erb_lba = 0;
do { do
{
// Read and validate the extended boot record // Read and validate the extended boot record
if (interface->readSectors(ebr_lba + next_erb_lba, 1, &sector)) { if ( interface->readSectors( ebr_lba + next_erb_lba, 1, &sector ) )
if (sector.ebr.signature == EBR_SIGNATURE) { {
if ( sector.ebr.signature == EBR_SIGNATURE )
{
ntfs_log_debug( "Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba, 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.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
sector.ebr.partition.type ); sector.ebr.partition.type );
@ -196,42 +216,54 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
next_erb_lba = le32_to_cpu( sector.ebr.next_ebr.lba_start ); next_erb_lba = le32_to_cpu( sector.ebr.next_ebr.lba_start );
// Check if this partition has a valid NTFS boot record // Check if this partition has a valid NTFS boot record
if (interface->readSectors(part_lba, 1, &sector)) { if ( interface->readSectors( part_lba, 1, &sector ) )
if (sector.boot.oem_id == NTFS_OEM_ID) { {
if ( sector.boot.oem_id == NTFS_OEM_ID )
{
ntfs_log_debug( "Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba ); 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 ); 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_starts[partition_count] = part_lba;
partition_count++; partition_count++;
} }
} }
} }
} else { }
else
{
next_erb_lba = 0; next_erb_lba = 0;
} }
} }
} while (next_erb_lba); }
while ( next_erb_lba );
break; break;
} }
// Unknown or unsupported partition type // Unknown or unsupported partition type
default: { default:
{
// Check if this partition has a valid NTFS boot record anyway, // Check if this partition has a valid NTFS boot record anyway,
// it might be misrepresented due to a lazy partition editor // it might be misrepresented due to a lazy partition editor
if (interface->readSectors(part_lba, 1, &sector)) { if ( interface->readSectors( part_lba, 1, &sector ) )
if (sector.boot.oem_id == NTFS_OEM_ID) { {
if ( sector.boot.oem_id == NTFS_OEM_ID )
{
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 ); 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 ); 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_starts[partition_count] = part_lba;
partition_count++; partition_count++;
} }
@ -247,15 +279,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
} }
// Else it is assumed this device has no master boot record // Else it is assumed this device has no master boot record
} else { }
else
{
ntfs_log_debug( "No Master Boot Record was found!\n" ); 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 // As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
for (i = 0; i < 64; i++) { for ( i = 0; i < 64; i++ )
if (interface->readSectors(i, 1, &sector)) { {
if (sector.boot.oem_id == NTFS_OEM_ID) { if ( interface->readSectors( i, 1, &sector ) )
{
if ( sector.boot.oem_id == NTFS_OEM_ID )
{
ntfs_log_debug( "Valid NTFS boot sector found at sector %d!\n", i ); 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_starts[partition_count] = i;
partition_count++; partition_count++;
} }
@ -269,9 +307,11 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
/*interface->shutdown();*/ /*interface->shutdown();*/
// Return the found partitions (if any) // Return the found partitions (if any)
if (partition_count > 0) { if ( partition_count > 0 )
{
*partitions = ( sec_t* )ntfs_alloc( sizeof( sec_t ) * partition_count ); *partitions = ( sec_t* )ntfs_alloc( sizeof( sec_t ) * partition_count );
if (*partitions) { if ( *partitions )
{
memcpy( *partitions, &partition_starts, sizeof( sec_t ) * partition_count ); memcpy( *partitions, &partition_starts, sizeof( sec_t ) * partition_count );
return partition_count; return partition_count;
} }
@ -295,25 +335,33 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
ntfsInit(); ntfsInit();
// Find and mount all NTFS partitions on all known devices // 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]; disc = &discs[i];
partition_count = ntfsFindPartitions( disc->interface, &partitions ); partition_count = ntfsFindPartitions( disc->interface, &partitions );
if (partition_count > 0 && partitions) { if ( partition_count > 0 && partitions )
for (j = 0, k = 0; j < partition_count; j++) { {
for ( j = 0, k = 0; j < partition_count; j++ )
{
// Find the next unused mount name // Find the next unused mount name
do { do
{
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ ); sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
if (k >= NTFS_MAX_MOUNTS) { if ( k >= NTFS_MAX_MOUNTS )
{
ntfs_free( partitions ); ntfs_free( partitions );
errno = EADDRNOTAVAIL; errno = EADDRNOTAVAIL;
return -1; return -1;
} }
} while (ntfsGetDevice(name, false)); }
while ( ntfsGetDevice( name, false ) );
// Mount the partition // Mount the partition
if (mount_count < NTFS_MAX_MOUNTS) { if ( mount_count < NTFS_MAX_MOUNTS )
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) { {
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
{
strcpy( mount_points[mount_count].name, name ); strcpy( mount_points[mount_count].name, name );
mount_points[mount_count].interface = disc->interface; mount_points[mount_count].interface = disc->interface;
mount_points[mount_count].startSector = partitions[j]; mount_points[mount_count].startSector = partitions[j];
@ -327,9 +375,11 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
} }
// Return the mounts (if any) // 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 ); *mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
if (*mounts) { if ( *mounts )
{
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count ); memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
return mount_count; return mount_count;
} }
@ -350,7 +400,8 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
int i, j, k; int i, j, k;
// Sanity check // Sanity check
if (!interface) { if ( !interface )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -359,26 +410,35 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
ntfsInit(); ntfsInit();
// Find the specified device then find and mount all NTFS partitions on it // 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++) { for ( i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++ )
if (discs[i].interface == interface) { {
if ( discs[i].interface == interface )
{
disc = &discs[i]; disc = &discs[i];
partition_count = ntfsFindPartitions( disc->interface, &partitions ); partition_count = ntfsFindPartitions( disc->interface, &partitions );
if (partition_count > 0 && partitions) { if ( partition_count > 0 && partitions )
for (j = 0, k = 0; j < partition_count; j++) { {
for ( j = 0, k = 0; j < partition_count; j++ )
{
// Find the next unused mount name // Find the next unused mount name
do { do
{
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ ); sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
if (k >= NTFS_MAX_MOUNTS) { if ( k >= NTFS_MAX_MOUNTS )
{
ntfs_free( partitions ); ntfs_free( partitions );
errno = EADDRNOTAVAIL; errno = EADDRNOTAVAIL;
return -1; return -1;
} }
} while (ntfsGetDevice(name, false)); }
while ( ntfsGetDevice( name, false ) );
// Mount the partition // Mount the partition
if (mount_count < NTFS_MAX_MOUNTS) { if ( mount_count < NTFS_MAX_MOUNTS )
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) { {
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
{
strcpy( mount_points[mount_count].name, name ); strcpy( mount_points[mount_count].name, name );
mount_points[mount_count].interface = disc->interface; mount_points[mount_count].interface = disc->interface;
mount_points[mount_count].startSector = partitions[j]; mount_points[mount_count].startSector = partitions[j];
@ -394,15 +454,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 we couldn't find the device then return with error status
if (!disc) { if ( !disc )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
// Return the mounts (if any) // 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 ); *mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
if (*mounts) { if ( *mounts )
{
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count ); memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
return mount_count; return mount_count;
} }
@ -417,7 +480,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
gekko_fd *fd = NULL; gekko_fd *fd = NULL;
// Sanity check // Sanity check
if (!name || !interface) { if ( !name || !interface )
{
errno = EINVAL; errno = EINVAL;
return false; return false;
} }
@ -426,20 +490,23 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
ntfsInit(); ntfsInit();
// Check that the requested mount name is free // Check that the requested mount name is free
if (ntfsGetDevice(name, false)) { if ( ntfsGetDevice( name, false ) )
{
errno = EADDRINUSE; errno = EADDRINUSE;
return false; return false;
} }
// Check that we can at least read from this device // Check that we can at least read from this device
if (!(interface->features & FEATURE_MEDIUM_CANREAD)) { if ( !( interface->features & FEATURE_MEDIUM_CANREAD ) )
{
errno = EPERM; errno = EPERM;
return false; return false;
} }
// Allocate the volume descriptor // Allocate the volume descriptor
vd = ( ntfs_vd* )ntfs_alloc( sizeof( ntfs_vd ) ); vd = ( ntfs_vd* )ntfs_alloc( sizeof( ntfs_vd ) );
if (!vd) { if ( !vd )
{
errno = ENOMEM; errno = ENOMEM;
return false; return false;
} }
@ -457,7 +524,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
// Allocate the device driver descriptor // Allocate the device driver descriptor
fd = ( gekko_fd* )ntfs_alloc( sizeof( gekko_fd ) ); fd = ( gekko_fd* )ntfs_alloc( sizeof( gekko_fd ) );
if (!fd) { if ( !fd )
{
ntfs_free( vd ); ntfs_free( vd );
errno = ENOMEM; errno = ENOMEM;
return false; return false;
@ -473,7 +541,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
// Allocate the device driver // Allocate the device driver
vd->dev = ntfs_device_alloc( name, 0, &ntfs_device_gekko_io_ops, fd ); vd->dev = ntfs_device_alloc( name, 0, &ntfs_device_gekko_io_ops, fd );
if (!vd->dev) { if ( !vd->dev )
{
ntfs_free( fd ); ntfs_free( fd );
ntfs_free( vd ); ntfs_free( vd );
return false; return false;
@ -499,8 +568,10 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
// Mount the device // Mount the device
vd->vol = ntfs_device_mount( vd->dev, vd->flags ); vd->vol = ntfs_device_mount( vd->dev, vd->flags );
if (!vd->vol) { if ( !vd->vol )
switch(ntfs_volume_error(errno)) { {
switch ( ntfs_volume_error( errno ) )
{
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break; case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break; case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break; case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
@ -513,14 +584,16 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
} }
// Initialise the volume descriptor // Initialise the volume descriptor
if (ntfsInitVolume(vd)) { if ( ntfsInitVolume( vd ) )
{
ntfs_umount( vd->vol, true ); ntfs_umount( vd->vol, true );
ntfs_free( vd ); ntfs_free( vd );
return false; return false;
} }
// Add the device to the devoptab table // Add the device to the devoptab table
if (ntfsAddDevice(name, vd)) { if ( ntfsAddDevice( name, vd ) )
{
ntfsDeinitVolume( vd ); ntfsDeinitVolume( vd );
ntfs_umount( vd->vol, true ); ntfs_umount( vd->vol, true );
ntfs_free( vd ); ntfs_free( vd );
@ -562,14 +635,16 @@ const char *ntfsGetVolumeName (const char *name)
//char *volumeName = NULL; //char *volumeName = NULL;
// Sanity check // Sanity check
if (!name) { if ( !name )
{
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
// Get the devices volume descriptor // Get the devices volume descriptor
vd = ntfsGetVolume( name ); vd = ntfsGetVolume( name );
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return NULL; return NULL;
} }
@ -642,14 +717,16 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
int ulabel_len; int ulabel_len;
// Sanity check // Sanity check
if (!name) { if ( !name )
{
errno = EINVAL; errno = EINVAL;
return false; return false;
} }
// Get the devices volume descriptor // Get the devices volume descriptor
vd = ntfsGetVolume( name ); vd = ntfsGetVolume( name );
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return false; return false;
} }
@ -659,7 +736,8 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
// Convert the new volume name to unicode // Convert the new volume name to unicode
ulabel_len = ntfsLocalToUnicode( volumeName, &ulabel ) * sizeof( ntfschar ); ulabel_len = ntfsLocalToUnicode( volumeName, &ulabel ) * sizeof( ntfschar );
if (ulabel_len < 0) { if ( ulabel_len < 0 )
{
ntfsUnlock( vd ); ntfsUnlock( vd );
errno = EINVAL; errno = EINVAL;
return false; return false;
@ -667,26 +745,32 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
// Check if the volume name attribute exists // Check if the volume name attribute exists
na = ntfs_attr_open( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0 ); 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 // 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 ); ntfs_free( ulabel );
ntfsUnlock( vd ); ntfsUnlock( vd );
return false; return false;
} }
// Write the new volume name // 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 ); ntfs_free( ulabel );
ntfsUnlock( vd ); ntfsUnlock( vd );
return false; return false;
} }
} else { }
else
{
// It doesn't, create it now // 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 ); ntfs_free( ulabel );
ntfsUnlock( vd ); ntfsUnlock( vd );
return false; return false;
@ -702,7 +786,8 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
ntfs_attr_close( na ); ntfs_attr_close( na );
// Sync the volume node // Sync the volume node
if (ntfs_inode_sync(vd->vol->vol_ni)) { if ( ntfs_inode_sync( vd->vol->vol_ni ) )
{
ntfs_free( ulabel ); ntfs_free( ulabel );
ntfsUnlock( vd ); ntfsUnlock( vd );
return false; return false;

View File

@ -23,7 +23,8 @@
#define _LIBNTFS_H #define _LIBNTFS_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
#include <gctypes.h> #include <gctypes.h>
@ -54,7 +55,8 @@ extern "C" {
/** /**
* ntfs_md - NTFS mount descriptor * ntfs_md - NTFS mount descriptor
*/ */
typedef struct _ntfs_md { typedef struct _ntfs_md
{
char name[32]; /* Mount name (can be accessed as "name:/") */ char name[32]; /* Mount name (can be accessed as "name:/") */
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */ const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
sec_t startSector; /* Local block address to first sector of partition */ sec_t startSector; /* Local block address to first sector of partition */

View File

@ -54,7 +54,8 @@ void ntfsCloseDir (ntfs_dir_state *dir)
return; return;
// Free the directory entries (if any) // Free the directory entries (if any)
while (dir->first) { while ( dir->first )
{
ntfs_dir_entry *next = dir->first->next; ntfs_dir_entry *next = dir->first->next;
ntfs_free( dir->first->name ); ntfs_free( dir->first->name );
ntfs_free( dir->first ); ntfs_free( dir->first );
@ -86,7 +87,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
// Get the volume descriptor for this path // Get the volume descriptor for this path
vd = ntfsGetVolume( path ); vd = ntfsGetVolume( path );
if (!vd) { if ( !vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -103,7 +105,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
// Find the entry // Find the entry
ni = ntfsOpenEntry( vd, path ); ni = ntfsOpenEntry( vd, path );
if (!ni) { if ( !ni )
{
r->_errno = errno; r->_errno = errno;
ntfsUnlock( vd ); ntfsUnlock( vd );
return -1; return -1;
@ -131,7 +134,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
// Get the volume descriptor for this path // Get the volume descriptor for this path
vd = ntfsGetVolume( existing ); vd = ntfsGetVolume( existing );
if (!vd) { if ( !vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -141,7 +145,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
// Create a symbolic link between the two paths // Create a symbolic link between the two paths
ni = ntfsCreate( vd, existing, S_IFLNK, newLink ); ni = ntfsCreate( vd, existing, S_IFLNK, newLink );
if (!ni) { if ( !ni )
{
ntfsUnlock( vd ); ntfsUnlock( vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
@ -177,7 +182,8 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
// Get the volume descriptor for this path // Get the volume descriptor for this path
vd = ntfsGetVolume( name ); vd = ntfsGetVolume( name );
if (!vd) { if ( !vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -187,14 +193,16 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
// Find the directory // Find the directory
ni = ntfsOpenEntry( vd, name ); ni = ntfsOpenEntry( vd, name );
if (!ni) { if ( !ni )
{
ntfsUnlock( vd ); ntfsUnlock( vd );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
} }
// Ensure that this directory is indeed a directory // 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 ); ntfsCloseEntry( vd, ni );
ntfsUnlock( vd ); ntfsUnlock( vd );
r->_errno = ENOTDIR; r->_errno = ENOTDIR;
@ -223,7 +231,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
// Get the volume descriptor for this path // Get the volume descriptor for this path
vd = ntfsGetVolume( oldName ); vd = ntfsGetVolume( oldName );
if (!vd) { if ( !vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -232,7 +241,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
ntfsLock( vd ); ntfsLock( vd );
// You cannot rename between devices // You cannot rename between devices
if(vd != ntfsGetVolume(newName)) { if ( vd != ntfsGetVolume( newName ) )
{
ntfsUnlock( vd ); ntfsUnlock( vd );
r->_errno = EXDEV; r->_errno = EXDEV;
return -1; return -1;
@ -240,7 +250,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 // Check that there is no existing entry with the new name
ni = ntfsOpenEntry( vd, newName ); ni = ntfsOpenEntry( vd, newName );
if (ni) { if ( ni )
{
ntfsCloseEntry( vd, ni ); ntfsCloseEntry( vd, ni );
ntfsUnlock( vd ); ntfsUnlock( vd );
r->_errno = EEXIST; r->_errno = EEXIST;
@ -248,14 +259,17 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
} }
// Link the old entry with the new one // Link the old entry with the new one
if (ntfsLink(vd, oldName, newName)) { if ( ntfsLink( vd, oldName, newName ) )
{
ntfsUnlock( vd ); ntfsUnlock( vd );
return -1; return -1;
} }
// Unlink the old entry // Unlink the old entry
if (ntfsUnlink(vd, oldName)) { if ( ntfsUnlink( vd, oldName ) )
if (ntfsUnlink(vd, newName)) { {
if ( ntfsUnlink( vd, newName ) )
{
ntfsUnlock( vd ); ntfsUnlock( vd );
return -1; return -1;
} }
@ -278,7 +292,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
// Get the volume descriptor for this path // Get the volume descriptor for this path
vd = ntfsGetVolume( path ); vd = ntfsGetVolume( path );
if (!vd) { if ( !vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -288,7 +303,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
// Create the directory // Create the directory
ni = ntfsCreate( vd, path, S_IFDIR, NULL ); ni = ntfsCreate( vd, path, S_IFDIR, NULL );
if (!ni) { if ( !ni )
{
ntfsUnlock( vd ); ntfsUnlock( vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
@ -313,7 +329,8 @@ int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
// Get the volume descriptor for this path // Get the volume descriptor for this path
vd = ntfsGetVolume( path ); vd = ntfsGetVolume( path );
if (!vd) { if ( !vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -387,21 +404,25 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
char *entry_name = NULL; char *entry_name = NULL;
// Sanity check // Sanity check
if (!dir || !dir->vd) { if ( !dir || !dir->vd )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
// Ignore DOS file names // Ignore DOS file names
if (name_type == FILE_NAME_DOS) { if ( name_type == FILE_NAME_DOS )
{
return 0; return 0;
} }
// Preliminary check that this entry can be enumerated (as described by the volume descriptor) // 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 // 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; return -1;
} }
@ -412,7 +433,8 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
} }
// If this is not the parent or self directory reference // 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 // Open the entry
ntfs_inode *ni = ntfs_pathname_to_inode( dir->vd->vol, dir->ni, entry_name ); ntfs_inode *ni = ntfs_pathname_to_inode( dir->vd->vol, dir->ni, entry_name );
@ -421,7 +443,8 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
// Double check that this entry can be emuerated (as described by the volume descriptor) // Double check that this entry can be emuerated (as described by the volume descriptor)
if ( ( ( ni->flags & FILE_ATTR_HIDDEN ) && !dir->vd->showHiddenFiles ) || if ( ( ( ni->flags & FILE_ATTR_HIDDEN ) && !dir->vd->showHiddenFiles ) ||
((ni->flags & FILE_ATTR_SYSTEM) && !dir->vd->showSystemFiles)) { ( ( ni->flags & FILE_ATTR_SYSTEM ) && !dir->vd->showSystemFiles ) )
{
ntfs_inode_close( ni ); ntfs_inode_close( ni );
return 0; return 0;
} }
@ -442,9 +465,12 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
entry->mref = MREF( mref ); entry->mref = MREF( mref );
// Link the entry to the directory // Link the entry to the directory
if (!dir->first) { if ( !dir->first )
{
dir->first = entry; dir->first = entry;
} else { }
else
{
ntfs_dir_entry *last = dir->first; ntfs_dir_entry *last = dir->first;
while ( last->next ) last = last->next; while ( last->next ) last = last->next;
last->next = entry; last->next = entry;
@ -464,7 +490,8 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
// Get the volume descriptor for this path // Get the volume descriptor for this path
dir->vd = ntfsGetVolume( path ); dir->vd = ntfsGetVolume( path );
if (!dir->vd) { if ( !dir->vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return NULL; return NULL;
} }
@ -474,14 +501,16 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
// Find the directory // Find the directory
dir->ni = ntfsOpenEntry( dir->vd, path ); dir->ni = ntfsOpenEntry( dir->vd, path );
if (!dir->ni) { if ( !dir->ni )
{
ntfsUnlock( dir->vd ); ntfsUnlock( dir->vd );
r->_errno = ENOENT; r->_errno = ENOENT;
return NULL; return NULL;
} }
// Ensure that this directory is indeed a directory // 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 ); ntfsCloseEntry( dir->vd, dir->ni );
ntfsUnlock( dir->vd ); ntfsUnlock( dir->vd );
r->_errno = ENOTDIR; r->_errno = ENOTDIR;
@ -490,7 +519,8 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
// Read the directory // Read the directory
dir->first = dir->current = NULL; 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 ); ntfsCloseDir( dir );
ntfsUnlock( dir->vd ); ntfsUnlock( dir->vd );
r->_errno = errno; r->_errno = errno;
@ -504,10 +534,13 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME ); ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
// Insert the directory into the double-linked FILO list of open directories // 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->nextOpenDir = dir->vd->firstOpenDir;
dir->vd->firstOpenDir->prevOpenDir = dir; dir->vd->firstOpenDir->prevOpenDir = dir;
} else { }
else
{
dir->nextOpenDir = NULL; dir->nextOpenDir = NULL;
} }
dir->prevOpenDir = NULL; dir->prevOpenDir = NULL;
@ -528,7 +561,8 @@ int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
ntfs_dir_state* dir = STATE( dirState ); ntfs_dir_state* dir = STATE( dirState );
// Sanity check // Sanity check
if (!dir || !dir->vd || !dir->ni) { if ( !dir || !dir->vd || !dir->ni )
{
r->_errno = EBADF; r->_errno = EBADF;
return -1; return -1;
} }
@ -556,7 +590,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
ntfs_inode *ni = NULL; ntfs_inode *ni = NULL;
// Sanity check // Sanity check
if (!dir || !dir->vd || !dir->ni) { if ( !dir || !dir->vd || !dir->ni )
{
r->_errno = EBADF; r->_errno = EBADF;
return -1; return -1;
} }
@ -565,7 +600,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
ntfsLock( dir->vd ); ntfsLock( dir->vd );
// Check that there is a entry waiting to be fetched // Check that there is a entry waiting to be fetched
if (!dir->current) { if ( !dir->current )
{
ntfsUnlock( dir->vd ); ntfsUnlock( dir->vd );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
@ -583,7 +619,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
else else
{ {
ni = ntfsOpenEntry( dir->vd, dir->current->name ); ni = ntfsOpenEntry( dir->vd, dir->current->name );
if (ni) { if ( ni )
{
ntfsStat( dir->vd, ni, filestat ); ntfsStat( dir->vd, ni, filestat );
ntfsCloseEntry( dir->vd, ni ); ntfsCloseEntry( dir->vd, ni );
} }
@ -609,7 +646,8 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
ntfs_dir_state* dir = STATE( dirState ); ntfs_dir_state* dir = STATE( dirState );
// Sanity check // Sanity check
if (!dir || !dir->vd) { if ( !dir || !dir->vd )
{
r->_errno = EBADF; r->_errno = EBADF;
return -1; return -1;
} }

View File

@ -28,7 +28,8 @@
/** /**
* ntfs_dir_entry - Directory entry * ntfs_dir_entry - Directory entry
*/ */
typedef struct _ntfs_dir_entry { typedef struct _ntfs_dir_entry
{
char *name; char *name;
u64 mref; u64 mref;
struct _ntfs_dir_entry *next; struct _ntfs_dir_entry *next;
@ -37,7 +38,8 @@ typedef struct _ntfs_dir_entry {
/** /**
* ntfs_dir_state - Directory state * ntfs_dir_state - Directory state
*/ */
typedef struct _ntfs_dir_state { typedef struct _ntfs_dir_state
{
ntfs_vd *vd; /* Volume this directory belongs to */ ntfs_vd *vd; /* Volume this directory belongs to */
ntfs_inode *ni; /* Directory descriptor */ ntfs_inode *ni; /* Directory descriptor */
ntfs_dir_entry *first; /* The first entry in the directory */ ntfs_dir_entry *first; /* The first entry in the directory */

View File

@ -97,7 +97,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Get the volume descriptor for this path // Get the volume descriptor for this path
file->vd = ntfsGetVolume( path ); file->vd = ntfsGetVolume( path );
if (!file->vd) { if ( !file->vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -107,19 +108,26 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Determine which mode the file is opened for // Determine which mode the file is opened for
file->flags = flags; file->flags = flags;
if ((flags & 0x03) == O_RDONLY) { if ( ( flags & 0x03 ) == O_RDONLY )
{
file->read = true; file->read = true;
file->write = false; file->write = false;
file->append = false; file->append = false;
} else if ((flags & 0x03) == O_WRONLY) { }
else if ( ( flags & 0x03 ) == O_WRONLY )
{
file->read = false; file->read = false;
file->write = true; file->write = true;
file->append = ( flags & O_APPEND ); file->append = ( flags & O_APPEND );
} else if ((flags & 0x03) == O_RDWR) { }
else if ( ( flags & 0x03 ) == O_RDWR )
{
file->read = true; file->read = true;
file->write = true; file->write = true;
file->append = ( flags & O_APPEND ); file->append = ( flags & O_APPEND );
} else { }
else
{
r->_errno = EACCES; r->_errno = EACCES;
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
return -1; return -1;
@ -127,7 +135,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 // Try and find the file and (if found) ensure that it is not a directory
file->ni = ntfsOpenEntry( file->vd, path ); 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 ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EISDIR; r->_errno = EISDIR;
@ -135,10 +144,12 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
} }
// Are we creating this file? // Are we creating this file?
if (flags & O_CREAT) { if ( flags & O_CREAT )
{
// The file SHOULD NOT already exist // The file SHOULD NOT already exist
if (file->ni) { if ( file->ni )
{
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EEXIST; r->_errno = EEXIST;
@ -147,7 +158,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Create the file // Create the file
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL ); file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
if (!file->ni) { if ( !file->ni )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
return -1; return -1;
} }
@ -155,7 +167,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
} }
// Sanity check, the file should be open by now // Sanity check, the file should be open by now
if (!file->ni) { if ( !file->ni )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
@ -163,7 +176,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Open the files data attribute // Open the files data attribute
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 ); 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 ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
return -1; return -1;
@ -174,7 +188,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 ); file->encrypted = NAttrEncrypted( file->data_na ) || ( file->ni->flags & FILE_ATTR_ENCRYPTED );
// We cannot read/write encrypted files // We cannot read/write encrypted files
if (file->encrypted) { if ( file->encrypted )
{
ntfs_attr_close( file->data_na ); ntfs_attr_close( file->data_na );
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
@ -183,7 +198,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 // 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 ); ntfs_attr_close( file->data_na );
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
@ -192,8 +208,10 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
} }
// Truncate the file if requested // Truncate the file if requested
if ((flags & O_TRUNC) && file->write) { if ( ( flags & O_TRUNC ) && file->write )
if (ntfs_attr_truncate(file->data_na, 0)) { {
if ( ntfs_attr_truncate( file->data_na, 0 ) )
{
ntfs_attr_close( file->data_na ); ntfs_attr_close( file->data_na );
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
@ -212,10 +230,13 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME ); ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
// Insert the file into the double-linked FILO list of open files // 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->nextOpenFile = file->vd->firstOpenFile;
file->vd->firstOpenFile->prevOpenFile = file; file->vd->firstOpenFile->prevOpenFile = file;
} else { }
else
{
file->nextOpenFile = NULL; file->nextOpenFile = NULL;
} }
file->prevOpenFile = NULL; file->prevOpenFile = NULL;
@ -235,7 +256,8 @@ int ntfs_close_r (struct _reent *r, int fd)
ntfs_file_state* file = STATE( fd ); ntfs_file_state* file = STATE( fd );
// Sanity check // Sanity check
if (!file || !file->vd) { if ( !file || !file->vd )
{
r->_errno = EBADF; r->_errno = EBADF;
return -1; return -1;
} }
@ -270,13 +292,15 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
off_t old_pos = 0; off_t old_pos = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
// Short circuit cases where we don't actually have to do anything // Short circuit cases where we don't actually have to do anything
if (!ptr || len <= 0) { if ( !ptr || len <= 0 )
{
return 0; return 0;
} }
@ -284,22 +308,26 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
ntfsLock( file->vd ); ntfsLock( file->vd );
// Check that we are allowed to write to this file // Check that we are allowed to write to this file
if (!file->write) { if ( !file->write )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EACCES; r->_errno = EACCES;
return -1; return -1;
} }
// If we are in append mode, backup the current position and move to the end of the file // 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; old_pos = file->pos;
file->pos = file->len; file->pos = file->len;
} }
// Write to the files data atrribute // Write to the files data atrribute
while (len) { while ( len )
{
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr ); ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
if (ret <= 0) { if ( ret <= 0 )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
@ -310,7 +338,8 @@ 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 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; file->pos = old_pos;
} }
@ -335,13 +364,15 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
ssize_t read = 0; ssize_t read = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
// Short circuit cases where we don't actually have to do anything // Short circuit cases where we don't actually have to do anything
if (!ptr || len <= 0) { if ( !ptr || len <= 0 )
{
return 0; return 0;
} }
@ -349,14 +380,16 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
ntfsLock( file->vd ); ntfsLock( file->vd );
// Check that we are allowed to read from this file // Check that we are allowed to read from this file
if (!file->read) { if ( !file->read )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EACCES; r->_errno = EACCES;
return -1; return -1;
} }
// Don't read past the end of file // Don't read past the end of file
if (file->pos + len > file->len) { if ( file->pos + len > file->len )
{
r->_errno = EOVERFLOW; r->_errno = EOVERFLOW;
len = file->len - file->pos; len = file->len - file->pos;
ntfs_log_trace( "EOVERFLOW" ); ntfs_log_trace( "EOVERFLOW" );
@ -365,9 +398,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 ); 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 // Read from the files data attribute
while (len) { while ( len )
{
ssize_t ret = ntfs_attr_pread( file->data_na, file->pos, len, ptr ); 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 ); ntfsUnlock( file->vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
@ -394,7 +429,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
off_t position = 0; off_t position = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -403,7 +439,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
ntfsLock( file->vd ); ntfsLock( file->vd );
// Set the files current position // Set the files current position
switch(dir) { switch ( dir )
{
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break; 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_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; case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
@ -422,7 +459,8 @@ int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
int ret = 0; int ret = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -446,7 +484,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
ntfs_file_state* file = STATE( fd ); ntfs_file_state* file = STATE( fd );
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -455,7 +494,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
ntfsLock( file->vd ); ntfsLock( file->vd );
// Check that we are allowed to write to this file // Check that we are allowed to write to this file
if (!file->write) { if ( !file->write )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EACCES; r->_errno = EACCES;
return -1; return -1;
@ -464,22 +504,28 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
// For compressed files, only deleting and expanding contents are implemented // For compressed files, only deleting and expanding contents are implemented
if ( file->compressed && if ( file->compressed &&
len > 0 && len > 0 &&
len < file->data_na->initialized_size) { len < file->data_na->initialized_size )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EOPNOTSUPP; r->_errno = EOPNOTSUPP;
return -1; return -1;
} }
// Resize the files data attribute, either by expanding or truncating // 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; 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 ); ntfsUnlock( file->vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
} }
} else { }
if (ntfs_attr_truncate(file->data_na, len)) { else
{
if ( ntfs_attr_truncate( file->data_na, len ) )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
@ -514,7 +560,8 @@ int ntfs_fsync_r (struct _reent *r, int fd)
int ret = 0; int ret = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }

View File

@ -32,7 +32,8 @@
/** /**
* ntfs_file_state - File state * ntfs_file_state - File state
*/ */
typedef struct _ntfs_file_state { typedef struct _ntfs_file_state
{
ntfs_vd *vd; /* Volume this file belongs to */ ntfs_vd *vd; /* Volume this file belongs to */
ntfs_inode *ni; /* File descriptor */ ntfs_inode *ni; /* File descriptor */
ntfs_attr *data_na; /* File data descriptor */ ntfs_attr *data_na; /* File data descriptor */

View File

@ -102,7 +102,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Get the volume descriptor for this path // Get the volume descriptor for this path
file->vd = ntfsGetVolume( path ); file->vd = ntfsGetVolume( path );
if (!file->vd) { if ( !file->vd )
{
r->_errno = ENODEV; r->_errno = ENODEV;
return -1; return -1;
} }
@ -112,19 +113,26 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Determine which mode the file is opened for // Determine which mode the file is opened for
file->flags = flags; file->flags = flags;
if ((flags & 0x03) == O_RDONLY) { if ( ( flags & 0x03 ) == O_RDONLY )
{
file->read = true; file->read = true;
file->write = false; file->write = false;
file->append = false; file->append = false;
} else if ((flags & 0x03) == O_WRONLY) { }
else if ( ( flags & 0x03 ) == O_WRONLY )
{
file->read = false; file->read = false;
file->write = true; file->write = true;
file->append = ( flags & O_APPEND ); file->append = ( flags & O_APPEND );
} else if ((flags & 0x03) == O_RDWR) { }
else if ( ( flags & 0x03 ) == O_RDWR )
{
file->read = true; file->read = true;
file->write = true; file->write = true;
file->append = ( flags & O_APPEND ); file->append = ( flags & O_APPEND );
} else { }
else
{
r->_errno = EACCES; r->_errno = EACCES;
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
return -1; return -1;
@ -132,7 +140,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 // Try and find the file and (if found) ensure that it is not a directory
file->ni = ntfsOpenEntry( file->vd, path ); 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 ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EISDIR; r->_errno = EISDIR;
@ -140,10 +149,12 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
} }
// Are we creating this file? // Are we creating this file?
if (flags & O_CREAT) { if ( flags & O_CREAT )
{
// The file SHOULD NOT already exist // The file SHOULD NOT already exist
if (file->ni) { if ( file->ni )
{
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EEXIST; r->_errno = EEXIST;
@ -152,7 +163,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Create the file // Create the file
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL ); file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
if (!file->ni) { if ( !file->ni )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
return -1; return -1;
} }
@ -160,7 +172,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
} }
// Sanity check, the file should be open by now // Sanity check, the file should be open by now
if (!file->ni) { if ( !file->ni )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = ENOENT; r->_errno = ENOENT;
return -1; return -1;
@ -168,7 +181,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Open the files data attribute // Open the files data attribute
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 ); 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 ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
return -1; return -1;
@ -179,7 +193,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 ); file->encrypted = NAttrEncrypted( file->data_na ) || ( file->ni->flags & FILE_ATTR_ENCRYPTED );
// We cannot read/write encrypted files // We cannot read/write encrypted files
if (file->encrypted) { if ( file->encrypted )
{
ntfs_attr_close( file->data_na ); ntfs_attr_close( file->data_na );
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
@ -188,7 +203,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 // 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 ); ntfs_attr_close( file->data_na );
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
@ -197,8 +213,10 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
} }
// Truncate the file if requested // Truncate the file if requested
if ((flags & O_TRUNC) && file->write) { if ( ( flags & O_TRUNC ) && file->write )
if (ntfs_attr_truncate(file->data_na, 0)) { {
if ( ntfs_attr_truncate( file->data_na, 0 ) )
{
ntfs_attr_close( file->data_na ); ntfs_attr_close( file->data_na );
ntfsCloseEntry( file->vd, file->ni ); ntfsCloseEntry( file->vd, file->ni );
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
@ -217,10 +235,13 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME ); ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
// Insert the file into the double-linked FILO list of open files // 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->nextOpenFile = file->vd->firstOpenFile;
file->vd->firstOpenFile->prevOpenFile = file; file->vd->firstOpenFile->prevOpenFile = file;
} else { }
else
{
file->nextOpenFile = NULL; file->nextOpenFile = NULL;
} }
file->prevOpenFile = NULL; file->prevOpenFile = NULL;
@ -240,7 +261,8 @@ int ntfs_close_r (struct _reent *r, int fd)
ntfs_file_state* file = STATE( fd ); ntfs_file_state* file = STATE( fd );
// Sanity check // Sanity check
if (!file || !file->vd) { if ( !file || !file->vd )
{
r->_errno = EBADF; r->_errno = EBADF;
return -1; return -1;
} }
@ -275,13 +297,15 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
off_t old_pos = 0; off_t old_pos = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
// Short circuit cases where we don't actually have to do anything // Short circuit cases where we don't actually have to do anything
if (!ptr || len <= 0) { if ( !ptr || len <= 0 )
{
return 0; return 0;
} }
@ -289,22 +313,26 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
ntfsLock( file->vd ); ntfsLock( file->vd );
// Check that we are allowed to write to this file // Check that we are allowed to write to this file
if (!file->write) { if ( !file->write )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EACCES; r->_errno = EACCES;
return -1; return -1;
} }
// If we are in append mode, backup the current position and move to the end of the file // 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; old_pos = file->pos;
file->pos = file->len; file->pos = file->len;
} }
// Write to the files data atrribute // Write to the files data atrribute
while (len) { while ( len )
{
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr ); ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
if (ret <= 0) { if ( ret <= 0 )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
@ -315,7 +343,8 @@ 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 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; file->pos = old_pos;
} }
@ -355,7 +384,8 @@ int _NTFS_get_fragments (const char *path,
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
//r->_errno = EINVAL; //r->_errno = EINVAL;
return -13; return -13;
} }
@ -389,10 +419,12 @@ int _NTFS_get_fragments (const char *path,
u64 len = file->len; u64 len = file->len;
// Read from the files data attribute // Read from the files data attribute
while (len) { while ( len )
{
s64 ret = ntfs_attr_getfragments( file->data_na, file->pos, s64 ret = ntfs_attr_getfragments( file->data_na, file->pos,
len, offset, append_fragment, callback_data ); len, offset, append_fragment, callback_data );
if (ret <= 0 || ret > len) { if ( ret <= 0 || ret > len )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
//r->_errno = errno; //r->_errno = errno;
ret_val = -14; ret_val = -14;
@ -436,7 +468,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
off_t position = 0; off_t position = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -445,7 +478,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
ntfsLock( file->vd ); ntfsLock( file->vd );
// Set the files current position // Set the files current position
switch(dir) { switch ( dir )
{
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break; 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_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; case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
@ -464,7 +498,8 @@ int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
int ret = 0; int ret = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -488,7 +523,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
ntfs_file_state* file = STATE( fd ); ntfs_file_state* file = STATE( fd );
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }
@ -497,7 +533,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
ntfsLock( file->vd ); ntfsLock( file->vd );
// Check that we are allowed to write to this file // Check that we are allowed to write to this file
if (!file->write) { if ( !file->write )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EACCES; r->_errno = EACCES;
return -1; return -1;
@ -506,22 +543,28 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
// For compressed files, only deleting and expanding contents are implemented // For compressed files, only deleting and expanding contents are implemented
if ( file->compressed && if ( file->compressed &&
len > 0 && len > 0 &&
len < file->data_na->initialized_size) { len < file->data_na->initialized_size )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = EOPNOTSUPP; r->_errno = EOPNOTSUPP;
return -1; return -1;
} }
// Resize the files data attribute, either by expanding or truncating // 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; 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 ); ntfsUnlock( file->vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
} }
} else { }
if (ntfs_attr_truncate(file->data_na, len)) { else
{
if ( ntfs_attr_truncate( file->data_na, len ) )
{
ntfsUnlock( file->vd ); ntfsUnlock( file->vd );
r->_errno = errno; r->_errno = errno;
return -1; return -1;
@ -556,7 +599,8 @@ int ntfs_fsync_r (struct _reent *r, int fd)
int ret = 0; int ret = 0;
// Sanity check // Sanity check
if (!file || !file->vd || !file->ni || !file->data_na) { if ( !file || !file->vd || !file->ni || !file->data_na )
{
r->_errno = EINVAL; r->_errno = EINVAL;
return -1; return -1;
} }

View File

@ -43,7 +43,8 @@
#include <sdcard/gcsd.h> #include <sdcard/gcsd.h>
#include <ogc/usbstorage.h> #include <ogc/usbstorage.h>
const INTERFACE_ID ntfs_disc_interfaces[] = { const INTERFACE_ID ntfs_disc_interfaces[] =
{
{ "sd", &__io_wiisd }, { "sd", &__io_wiisd },
{ "usb", &__io_usbstorage }, { "usb", &__io_usbstorage },
{ "carda", &__io_gcsda }, { "carda", &__io_gcsda },
@ -54,7 +55,8 @@ const INTERFACE_ID ntfs_disc_interfaces[] = {
#elif defined(__gamecube__) #elif defined(__gamecube__)
#include <sdcard/gcsd.h> #include <sdcard/gcsd.h>
const INTERFACE_ID ntfs_disc_interfaces[] = { const INTERFACE_ID ntfs_disc_interfaces[] =
{
{ "carda", &__io_gcsda }, { "carda", &__io_gcsda },
{ "cardb", &__io_gcsdb }, { "cardb", &__io_gcsdb },
{ NULL, NULL } { NULL, NULL }
@ -70,14 +72,16 @@ int ntfsAddDevice (const char *name, void *deviceData)
int i; int i;
// Sanity check // Sanity check
if (!name || !deviceData || !devoptab_ntfs) { if ( !name || !deviceData || !devoptab_ntfs )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
// Allocate a devoptab for this device // Allocate a devoptab for this device
dev = ( devoptab_t * ) ntfs_alloc( sizeof( devoptab_t ) + strlen( name ) + 1 ); dev = ( devoptab_t * ) ntfs_alloc( sizeof( devoptab_t ) + strlen( name ) + 1 );
if (!dev) { if ( !dev )
{
errno = ENOMEM; errno = ENOMEM;
return false; return false;
} }
@ -92,8 +96,10 @@ int ntfsAddDevice (const char *name, void *deviceData)
dev->deviceData = deviceData; dev->deviceData = deviceData;
// Add the device to the devoptab table (if there is a free slot) // Add the device to the devoptab table (if there is a free slot)
for (i = 0; i < STD_MAX; i++) { for ( i = 0; i < STD_MAX; i++ )
if (devoptab_list[i] == devoptab_list[0] && i != 0) { {
if ( devoptab_list[i] == devoptab_list[0] && i != 0 )
{
devoptab_list[i] = dev; devoptab_list[i] = dev;
return 0; return 0;
} }
@ -118,10 +124,13 @@ void ntfsRemoveDevice (const char *path)
// NOTE: We do this manually due to a 'bug' in RemoveDevice // NOTE: We do this manually due to a 'bug' in RemoveDevice
// which ignores names with suffixes and causes names // which ignores names with suffixes and causes names
// like "ntfs" and "ntfs1" to be seen as equals // like "ntfs" and "ntfs1" to be seen as equals
for (i = 0; i < STD_MAX; i++) { for ( i = 0; i < STD_MAX; i++ )
{
devoptab = devoptab_list[i]; devoptab = devoptab_list[i];
if (devoptab && devoptab->name) { if ( devoptab && devoptab->name )
if (strcmp(name, devoptab->name) == 0) { {
if ( strcmp( name, devoptab->name ) == 0 )
{
devoptab_list[i] = devoptab_list[0]; devoptab_list[i] = devoptab_list[0];
ntfs_free( ( devoptab_t* )devoptab ); ntfs_free( ( devoptab_t* )devoptab );
break; break;
@ -146,10 +155,13 @@ const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice)
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
// which ignores names with suffixes and causes names // which ignores names with suffixes and causes names
// like "ntfs" and "ntfs1" to be seen as equals // like "ntfs" and "ntfs1" to be seen as equals
for (i = 0; i < STD_MAX; i++) { for ( i = 0; i < STD_MAX; i++ )
{
devoptab = devoptab_list[i]; devoptab = devoptab_list[i];
if (devoptab && devoptab->name) { if ( devoptab && devoptab->name )
if (strcmp(name, devoptab->name) == 0) { {
if ( strcmp( name, devoptab->name ) == 0 )
{
return devoptab; return devoptab;
} }
} }
@ -184,7 +196,8 @@ ntfs_vd *ntfsGetVolume (const char *path)
int ntfsInitVolume ( ntfs_vd *vd ) int ntfsInitVolume ( ntfs_vd *vd )
{ {
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
@ -210,7 +223,8 @@ int ntfsInitVolume (ntfs_vd *vd)
void ntfsDeinitVolume ( ntfs_vd *vd ) void ntfsDeinitVolume ( ntfs_vd *vd )
{ {
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return; return;
} }
@ -220,7 +234,8 @@ void ntfsDeinitVolume (ntfs_vd *vd)
// Close any directories which are still open (lazy programmers!) // Close any directories which are still open (lazy programmers!)
ntfs_dir_state *nextDir = vd->firstOpenDir; ntfs_dir_state *nextDir = vd->firstOpenDir;
while (nextDir) { while ( nextDir )
{
ntfs_log_warning( "Cleaning up orphaned directory @ %p\n", nextDir ); ntfs_log_warning( "Cleaning up orphaned directory @ %p\n", nextDir );
ntfsCloseDir( nextDir ); ntfsCloseDir( nextDir );
nextDir = nextDir->nextOpenDir; nextDir = nextDir->nextOpenDir;
@ -228,7 +243,8 @@ void ntfsDeinitVolume (ntfs_vd *vd)
// Close any files which are still open (lazy programmers!) // Close any files which are still open (lazy programmers!)
ntfs_file_state *nextFile = vd->firstOpenFile; ntfs_file_state *nextFile = vd->firstOpenFile;
while (nextFile) { while ( nextFile )
{
ntfs_log_warning( "Cleaning up orphaned file @ %p\n", nextFile ); ntfs_log_warning( "Cleaning up orphaned file @ %p\n", nextFile );
ntfsCloseFile( nextFile ); ntfsCloseFile( nextFile );
nextFile = nextFile->nextOpenFile; nextFile = nextFile->nextOpenFile;
@ -270,17 +286,21 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
int attr_size; int attr_size;
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return NULL; return NULL;
} }
// Get the actual path of the entry // Get the actual path of the entry
path = ntfsRealPath( path ); path = ntfsRealPath( path );
if (!path) { if ( !path )
{
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} else if (path[0] == '\0') { }
else if ( path[0] == '\0' )
{
path = "."; path = ".";
} }
@ -292,11 +312,14 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
// If the entry was found and it has reparse data then parse its true path; // If the entry was found and it has reparse data then parse its true path;
// this resolves the true location of symbolic links and directory junctions // this resolves the true location of symbolic links and directory junctions
if (ni && (ni->flags & FILE_ATTR_REPARSE_POINT)) { if ( ni && ( ni->flags & FILE_ATTR_REPARSE_POINT ) )
if (ntfs_possible_symlink(ni)) { {
if ( ntfs_possible_symlink( ni ) )
{
// Sanity check, give up if we are parsing to deep // Sanity check, give up if we are parsing to deep
if (reparseLevel > NTFS_MAX_SYMLINK_DEPTH) { if ( reparseLevel > NTFS_MAX_SYMLINK_DEPTH )
{
ntfsCloseEntry( vd, ni ); ntfsCloseEntry( vd, ni );
errno = ELOOP; errno = ELOOP;
return NULL; return NULL;
@ -304,7 +327,8 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
// Get the target path of this entry // Get the target path of this entry
target = ntfs_make_symlink( ni, path, &attr_size ); target = ntfs_make_symlink( ni, path, &attr_size );
if (!target) { if ( !target )
{
ntfsCloseEntry( vd, ni ); ntfsCloseEntry( vd, ni );
return NULL; return NULL;
} }
@ -327,7 +351,8 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
void ntfsCloseEntry ( ntfs_vd *vd, ntfs_inode *ni ) void ntfsCloseEntry ( ntfs_vd *vd, ntfs_inode *ni )
{ {
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return; return;
} }
@ -358,14 +383,17 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
int uname_len, utarget_len; int uname_len, utarget_len;
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return NULL; return NULL;
} }
// You cannot link between devices // You cannot link between devices
if(target) { if ( target )
if(vd != ntfsGetVolume(target)) { {
if ( vd != ntfsGetVolume( target ) )
{
errno = EXDEV; errno = EXDEV;
return NULL; return NULL;
} }
@ -374,7 +402,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
// Get the actual paths of the entry // Get the actual paths of the entry
path = ntfsRealPath( path ); path = ntfsRealPath( path );
target = ntfsRealPath( target ); target = ntfsRealPath( target );
if (!path) { if ( !path )
{
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
@ -385,7 +414,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
// Get the unicode name for the entry and find its parent directory // Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible, clean it up // TODO: This looks horrible, clean it up
dir = strdup( path ); dir = strdup( path );
if (!dir) { if ( !dir )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
@ -395,7 +425,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
else else
name = dir; name = dir;
uname_len = ntfsLocalToUnicode( name, &uname ); uname_len = ntfsLocalToUnicode( name, &uname );
if (uname_len < 0) { if ( uname_len < 0 )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
@ -408,21 +439,25 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
// Open the entries parent directory // Open the entries parent directory
dir_ni = ntfsOpenEntry( vd, dir ); dir_ni = ntfsOpenEntry( vd, dir );
if (!dir_ni) { if ( !dir_ni )
{
goto cleanup; goto cleanup;
} }
// Create the entry // Create the entry
switch (type) { switch ( type )
{
// Symbolic link // Symbolic link
case S_IFLNK: case S_IFLNK:
if (!target) { if ( !target )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
utarget_len = ntfsLocalToUnicode( target, &utarget ); utarget_len = ntfsLocalToUnicode( target, &utarget );
if (utarget_len < 0) { if ( utarget_len < 0 )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
@ -438,7 +473,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
} }
// If the entry was created // If the entry was created
if (ni) { if ( ni )
{
// Mark the entry for archiving // Mark the entry for archiving
ni->flags |= FILE_ATTR_ARCHIVE; ni->flags |= FILE_ATTR_ARCHIVE;
@ -484,13 +520,15 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
int res = 0; int res = 0;
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
// You cannot link between devices // You cannot link between devices
if(vd != ntfsGetVolume(new_path)) { if ( vd != ntfsGetVolume( new_path ) )
{
errno = EXDEV; errno = EXDEV;
return -1; return -1;
} }
@ -498,7 +536,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
// Get the actual paths of the entry // Get the actual paths of the entry
old_path = ntfsRealPath( old_path ); old_path = ntfsRealPath( old_path );
new_path = ntfsRealPath( new_path ); new_path = ntfsRealPath( new_path );
if (!old_path || !new_path) { if ( !old_path || !new_path )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -509,7 +548,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
// Get the unicode name for the entry and find its parent directory // Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible, clean it up // TODO: This looks horrible, clean it up
dir = strdup( new_path ); dir = strdup( new_path );
if (!dir) { if ( !dir )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
@ -519,7 +559,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
else else
name = dir; name = dir;
uname_len = ntfsLocalToUnicode( name, &uname ); uname_len = ntfsLocalToUnicode( name, &uname );
if (uname_len < 0) { if ( uname_len < 0 )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
@ -527,7 +568,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
// Find the entry // Find the entry
ni = ntfsOpenEntry( vd, old_path ); ni = ntfsOpenEntry( vd, old_path );
if (!ni) { if ( !ni )
{
errno = ENOENT; errno = ENOENT;
res = -1; res = -1;
goto cleanup; goto cleanup;
@ -535,14 +577,16 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
// Open the entries new parent directory // Open the entries new parent directory
dir_ni = ntfsOpenEntry( vd, dir ); dir_ni = ntfsOpenEntry( vd, dir );
if (!dir_ni) { if ( !dir_ni )
{
errno = ENOENT; errno = ENOENT;
res = -1; res = -1;
goto cleanup; goto cleanup;
} }
// Link the entry to its new parent // Link the entry to its new parent
if (ntfs_link(ni, dir_ni, uname, uname_len)) { if ( ntfs_link( ni, dir_ni, uname, uname_len ) )
{
res = -1; res = -1;
goto cleanup; goto cleanup;
} }
@ -583,14 +627,16 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
int res = 0; int res = 0;
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
// Get the actual path of the entry // Get the actual path of the entry
path = ntfsRealPath( path ); path = ntfsRealPath( path );
if (!path) { if ( !path )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -601,7 +647,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
// Get the unicode name for the entry and find its parent directory // Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible // TODO: This looks horrible
dir = strdup( path ); dir = strdup( path );
if (!dir) { if ( !dir )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
@ -611,7 +658,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
else else
name = dir; name = dir;
uname_len = ntfsLocalToUnicode( name, &uname ); uname_len = ntfsLocalToUnicode( name, &uname );
if (uname_len < 0) { if ( uname_len < 0 )
{
errno = EINVAL; errno = EINVAL;
goto cleanup; goto cleanup;
} }
@ -624,7 +672,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
// Find the entry // Find the entry
ni = ntfsOpenEntry( vd, path ); ni = ntfsOpenEntry( vd, path );
if (!ni) { if ( !ni )
{
errno = ENOENT; errno = ENOENT;
res = -1; res = -1;
goto cleanup; goto cleanup;
@ -632,14 +681,16 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
// Open the entries parent directory // Open the entries parent directory
dir_ni = ntfsOpenEntry( vd, dir ); dir_ni = ntfsOpenEntry( vd, dir );
if (!dir_ni) { if ( !dir_ni )
{
errno = ENOENT; errno = ENOENT;
res = -1; res = -1;
goto cleanup; goto cleanup;
} }
// Unlink the entry from its parent // Unlink the entry from its parent
if (ntfs_delete(vd->vol, path, ni, dir_ni, uname, uname_len)) { if ( ntfs_delete( vd->vol, path, ni, dir_ni, uname, uname_len ) )
{
res = -1; res = -1;
} }
@ -674,13 +725,15 @@ int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)
int res = 0; int res = 0;
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
// Sanity check // Sanity check
if (!ni) { if ( !ni )
{
errno = ENOENT; errno = ENOENT;
return -1; return -1;
} }
@ -707,13 +760,15 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
int res = 0; int res = 0;
// Sanity check // Sanity check
if (!vd) { if ( !vd )
{
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
// Sanity check // Sanity check
if (!ni) { if ( !ni )
{
errno = ENOENT; errno = ENOENT;
return -1; return -1;
} }
@ -729,20 +784,24 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
memset( st, 0, sizeof( struct stat ) ); memset( st, 0, sizeof( struct stat ) );
// Is this entry a directory // Is this entry a directory
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { if ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
{
st->st_mode = S_IFDIR | ( 0777 & ~vd->dmask ); st->st_mode = S_IFDIR | ( 0777 & ~vd->dmask );
st->st_nlink = 1; st->st_nlink = 1;
// Open the directories index allocation table attribute // Open the directories index allocation table attribute
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4 ); na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4 );
if (na) { if ( na )
{
st->st_size = na->data_size; st->st_size = na->data_size;
st->st_blocks = na->allocated_size >> 9; st->st_blocks = na->allocated_size >> 9;
ntfs_attr_close( na ); ntfs_attr_close( na );
} }
// Else it must be a file // Else it must be a file
} else { }
else
{
st->st_mode = S_IFREG | ( 0777 & ~vd->fmask ); st->st_mode = S_IFREG | ( 0777 & ~vd->fmask );
st->st_size = ni->data_size; st->st_size = ni->data_size;
st->st_blocks = ( ni->allocated_size + 511 ) >> 9; st->st_blocks = ( ni->allocated_size + 511 ) >> 9;
@ -787,10 +846,12 @@ const char *ntfsRealPath (const char *path)
return NULL; return NULL;
// Move the path pointer to the start of the actual path // Move the path pointer to the start of the actual path
if (strchr(path, ':') != NULL) { if ( strchr( path, ':' ) != NULL )
{
path = strchr( path, ':' ) + 1; path = strchr( path, ':' ) + 1;
} }
if (strchr(path, ':') != NULL) { if ( strchr( path, ':' ) != NULL )
{
return NULL; return NULL;
} }
@ -808,19 +869,24 @@ int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int
// Convert the unicode string to our current local // Convert the unicode string to our current local
len = ntfs_ucstombs( ins, ins_len, outs, outs_len ); len = ntfs_ucstombs( ins, ins_len, outs, outs_len );
if (len == -1 && errno == EILSEQ) { if ( len == -1 && errno == EILSEQ )
{
// The string could not be converted to the current local, // The string could not be converted to the current local,
// do it manually by replacing non-ASCII characters with underscores // do it manually by replacing non-ASCII characters with underscores
if (!*outs || outs_len >= ins_len) { if ( !*outs || outs_len >= ins_len )
if (!*outs) { {
if ( !*outs )
{
*outs = ( char * ) ntfs_alloc( ins_len + 1 ); *outs = ( char * ) ntfs_alloc( ins_len + 1 );
if (!*outs) { if ( !*outs )
{
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
} }
for (i = 0; i < ins_len; i++) { for ( i = 0; i < ins_len; i++ )
{
ntfschar uc = le16_to_cpu( ins[i] ); ntfschar uc = le16_to_cpu( ins[i] );
if ( uc > 0xff ) if ( uc > 0xff )
uc = ( ntfschar )'_'; uc = ( ntfschar )'_';

View File

@ -69,7 +69,8 @@ struct _ntfs_dir_state;
/** /**
* PRIMARY_PARTITION - Block device partition record * PRIMARY_PARTITION - Block device partition record
*/ */
typedef struct _PARTITION_RECORD { typedef struct _PARTITION_RECORD
{
u8 status; /* Partition status; see above */ u8 status; /* Partition status; see above */
u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */ u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */
u8 type; /* Partition type; see above */ u8 type; /* Partition type; see above */
@ -81,7 +82,8 @@ typedef struct _PARTITION_RECORD {
/** /**
* MASTER_BOOT_RECORD - Block device master boot record * MASTER_BOOT_RECORD - Block device master boot record
*/ */
typedef struct _MASTER_BOOT_RECORD { typedef struct _MASTER_BOOT_RECORD
{
u8 code_area[446]; /* Code area; normally empty */ u8 code_area[446]; /* Code area; normally empty */
PARTITION_RECORD partitions[4]; /* 4 primary partitions */ PARTITION_RECORD partitions[4]; /* 4 primary partitions */
u16 signature; /* MBR signature; 0xAA55 */ u16 signature; /* MBR signature; 0xAA55 */
@ -90,7 +92,8 @@ typedef struct _MASTER_BOOT_RECORD {
/** /**
* EXTENDED_PARTITION - Block device extended boot record * EXTENDED_PARTITION - Block device extended boot record
*/ */
typedef struct _EXTENDED_BOOT_RECORD { typedef struct _EXTENDED_BOOT_RECORD
{
u8 code_area[446]; /* Code area; normally empty */ u8 code_area[446]; /* Code area; normally empty */
PARTITION_RECORD partition; /* Primary partition */ PARTITION_RECORD partition; /* Primary partition */
PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */ PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */
@ -101,7 +104,8 @@ typedef struct _EXTENDED_BOOT_RECORD {
/** /**
* INTERFACE_ID - Disc interface identifier * INTERFACE_ID - Disc interface identifier
*/ */
typedef struct _INTERFACE_ID { typedef struct _INTERFACE_ID
{
const char *name; /* Interface name */ const char *name; /* Interface name */
const DISC_INTERFACE *interface; /* Disc interface */ const DISC_INTERFACE *interface; /* Disc interface */
} INTERFACE_ID; } INTERFACE_ID;
@ -109,7 +113,8 @@ typedef struct _INTERFACE_ID {
/** /**
* ntfs_atime_t - File access time update strategies * ntfs_atime_t - File access time update strategies
*/ */
typedef enum { typedef enum
{
ATIME_ENABLED, /* Update access times */ ATIME_ENABLED, /* Update access times */
ATIME_DISABLED /* Don't update access times */ ATIME_DISABLED /* Don't update access times */
} ntfs_atime_t; } ntfs_atime_t;
@ -117,7 +122,8 @@ typedef enum {
/** /**
* ntfs_vd - NTFS volume descriptor * ntfs_vd - NTFS volume descriptor
*/ */
typedef struct _ntfs_vd { typedef struct _ntfs_vd
{
struct ntfs_device *dev; /* NTFS device handle */ struct ntfs_device *dev; /* NTFS device handle */
ntfs_volume *vol; /* NTFS volume handle */ ntfs_volume *vol; /* NTFS volume handle */
mutex_t lock; /* Volume lock mutex */ mutex_t lock; /* Volume lock mutex */

View File

@ -106,25 +106,29 @@
* ---------------------- end from RFC 4122 ----------------------- * ---------------------- end from RFC 4122 -----------------------
*/ */
typedef struct { typedef struct
{
GUID object_id; GUID object_id;
} OBJECT_ID_INDEX_KEY; } OBJECT_ID_INDEX_KEY;
typedef struct { typedef struct
{
le64 file_id; le64 file_id;
GUID birth_volume_id; GUID birth_volume_id;
GUID birth_object_id; GUID birth_object_id;
GUID domain_id; GUID domain_id;
} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA } OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */ struct OBJECT_ID_INDEX /* index entry in $Extend/$ObjId */
{
INDEX_ENTRY_HEADER header; INDEX_ENTRY_HEADER header;
OBJECT_ID_INDEX_KEY key; OBJECT_ID_INDEX_KEY key;
OBJECT_ID_INDEX_DATA data; OBJECT_ID_INDEX_DATA data;
} ; } ;
static ntfschar objid_index_name[] = { const_cpu_to_le16( '$' ), static ntfschar objid_index_name[] = { const_cpu_to_le16( '$' ),
const_cpu_to_le16('O') }; const_cpu_to_le16( 'O' )
};
#ifdef HAVE_SETXATTR /* extended attributes interface required */ #ifdef HAVE_SETXATTR /* extended attributes interface required */
/* /*
@ -192,18 +196,22 @@ static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
/* do not use path_name_to inode - could reopen root */ /* do not use path_name_to inode - could reopen root */
dir_ni = ntfs_inode_open( vol, FILE_Extend ); dir_ni = ntfs_inode_open( vol, FILE_Extend );
ni = ( ntfs_inode* )NULL; ni = ( ntfs_inode* )NULL;
if (dir_ni) { if ( dir_ni )
{
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$ObjId" ); inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$ObjId" );
if ( inum != ( u64 ) - 1 ) if ( inum != ( u64 ) - 1 )
ni = ntfs_inode_open( vol, inum ); ni = ntfs_inode_open( vol, inum );
ntfs_inode_close( dir_ni ); ntfs_inode_close( dir_ni );
} }
if (ni) { if ( ni )
{
xo = ntfs_index_ctx_get( ni, objid_index_name, 2 ); xo = ntfs_index_ctx_get( ni, objid_index_name, 2 );
if (!xo) { if ( !xo )
{
ntfs_inode_close( ni ); ntfs_inode_close( ni );
} }
} else }
else
xo = ( ntfs_index_context* )NULL; xo = ( ntfs_index_context* )NULL;
return ( xo ); return ( xo );
} }
@ -230,15 +238,18 @@ static int merge_index_data(ntfs_inode *ni,
res = -1; res = -1;
xo = open_object_id_index( ni->vol ); xo = open_object_id_index( ni->vol );
if (xo) { if ( xo )
{
memcpy( &key.object_id, objectid_attr, sizeof( GUID ) ); memcpy( &key.object_id, objectid_attr, sizeof( GUID ) );
if ( !ntfs_index_lookup( &key, if ( !ntfs_index_lookup( &key,
sizeof(OBJECT_ID_INDEX_KEY), xo)) { sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
{
entry = ( struct OBJECT_ID_INDEX* )xo->entry; entry = ( struct OBJECT_ID_INDEX* )xo->entry;
/* make sure inode numbers match */ /* make sure inode numbers match */
if ( entry if ( entry
&& ( MREF( le64_to_cpu( entry->data.file_id ) ) && ( MREF( le64_to_cpu( entry->data.file_id ) )
== ni->mft_no)) { == ni->mft_no ) )
{
memcpy( &full_objectid->birth_volume_id, memcpy( &full_objectid->birth_volume_id,
&entry->data.birth_volume_id, &entry->data.birth_volume_id,
sizeof( GUID ) ); sizeof( GUID ) );
@ -277,15 +288,18 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
int ret; int ret;
ret = na->data_size; ret = na->data_size;
if (ret) { if ( ret )
{
/* read the existing object id attribute */ /* read the existing object id attribute */
size = ntfs_attr_pread( na, 0, sizeof( GUID ), old_attr ); size = ntfs_attr_pread( na, 0, sizeof( GUID ), old_attr );
if (size >= (s64)sizeof(GUID)) { if ( size >= ( s64 )sizeof( GUID ) )
{
memcpy( &key.object_id, memcpy( &key.object_id,
&old_attr->object_id, sizeof( GUID ) ); &old_attr->object_id, sizeof( GUID ) );
size = sizeof( GUID ); size = sizeof( GUID );
if ( !ntfs_index_lookup( &key, if ( !ntfs_index_lookup( &key,
sizeof(OBJECT_ID_INDEX_KEY), xo)) { sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
{
entry = ( struct OBJECT_ID_INDEX* )xo->entry; entry = ( struct OBJECT_ID_INDEX* )xo->entry;
memcpy( &old_attr->birth_volume_id, memcpy( &old_attr->birth_volume_id,
&entry->data.birth_volume_id, &entry->data.birth_volume_id,
@ -300,7 +314,9 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
if ( ntfs_index_rm( xo ) ) if ( ntfs_index_rm( xo ) )
ret = -1; ret = -1;
} }
} else { }
else
{
ret = -1; ret = -1;
errno = ENODATA; errno = ENODATA;
} }
@ -335,21 +351,25 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
res = 0; res = 0;
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 ); na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
if (na) { if ( na )
{
/* remove the existing index entry */ /* remove the existing index entry */
oldsize = remove_object_id_index( na, xo, &old_attr ); oldsize = remove_object_id_index( na, xo, &old_attr );
if ( oldsize < 0 ) if ( oldsize < 0 )
res = -1; res = -1;
else { else
{
/* resize attribute */ /* resize attribute */
res = ntfs_attr_truncate( na, ( s64 )sizeof( GUID ) ); res = ntfs_attr_truncate( na, ( s64 )sizeof( GUID ) );
/* write the object_id in attribute */ /* write the object_id in attribute */
if (!res && value) { if ( !res && value )
{
written = ( int )ntfs_attr_pwrite( na, written = ( int )ntfs_attr_pwrite( na,
( s64 )0, ( s64 )sizeof( GUID ), ( s64 )0, ( s64 )sizeof( GUID ),
&value->object_id ); &value->object_id );
if (written != (s64)sizeof(GUID)) { if ( written != ( s64 )sizeof( GUID ) )
{
ntfs_log_error( "Failed to update " ntfs_log_error( "Failed to update "
"object id\n" ); "object id\n" );
errno = EIO; errno = EIO;
@ -359,7 +379,8 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
/* write index part if provided */ /* write index part if provided */
if ( !res if ( !res
&& ( ( size < sizeof( OBJECT_ID_ATTR ) ) && ( ( size < sizeof( OBJECT_ID_ATTR ) )
|| set_object_id_index(ni,xo,value))) { || set_object_id_index( ni, xo, value ) ) )
{
/* /*
* If cannot index, try to remove the object * If cannot index, try to remove the object
* id and log the error. There will be an * id and log the error. There will be an
@ -372,7 +393,8 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
} }
ntfs_attr_close( na ); ntfs_attr_close( na );
NInoSetDirty( ni ); NInoSetDirty( ni );
} else }
else
res = -1; res = -1;
return ( res ); return ( res );
} }
@ -390,22 +412,29 @@ static int add_object_id(ntfs_inode *ni, int flags)
u8 dummy; u8 dummy;
res = -1; /* default return */ res = -1; /* default return */
if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) { if ( !ntfs_attr_exist( ni, AT_OBJECT_ID, AT_UNNAMED, 0 ) )
if (!(flags & XATTR_REPLACE)) { {
if ( !( flags & XATTR_REPLACE ) )
{
/* /*
* no object id attribute : add one, * no object id attribute : add one,
* apparently, this does not feed the new value in * apparently, this does not feed the new value in
* Note : NTFS version must be >= 3 * Note : NTFS version must be >= 3
*/ */
if (ni->vol->major_ver >= 3) { if ( ni->vol->major_ver >= 3 )
{
res = ntfs_attr_add( ni, AT_OBJECT_ID, res = ntfs_attr_add( ni, AT_OBJECT_ID,
AT_UNNAMED, 0, &dummy, ( s64 )0 ); AT_UNNAMED, 0, &dummy, ( s64 )0 );
NInoSetDirty( ni ); NInoSetDirty( ni );
} else }
else
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
} else }
else
errno = ENODATA; errno = ENODATA;
} else { }
else
{
if ( flags & XATTR_CREATE ) if ( flags & XATTR_CREATE )
errno = EEXIST; errno = EEXIST;
else else
@ -433,13 +462,15 @@ int ntfs_delete_object_id_index(ntfs_inode *ni)
res = 0; res = 0;
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 ); na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
if (na) { if ( na )
{
/* /*
* read the existing object id * read the existing object id
* and un-index it * and un-index it
*/ */
xo = open_object_id_index( ni->vol ); xo = open_object_id_index( ni->vol );
if (xo) { if ( xo )
{
if ( remove_object_id_index( na, xo, &old_attr ) < 0 ) if ( remove_object_id_index( na, xo, &old_attr ) < 0 )
res = -1; res = -1;
xoni = xo->ni; xoni = xo->ni;
@ -473,34 +504,42 @@ int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size)
int full_size; int full_size;
full_size = 0; /* default to no data and some error to be defined */ full_size = 0; /* default to no data and some error to be defined */
if (ni) { if ( ni )
{
objectid_attr = ( OBJECT_ID_ATTR* )ntfs_attr_readall( ni, objectid_attr = ( OBJECT_ID_ATTR* )ntfs_attr_readall( ni,
AT_OBJECT_ID, ( ntfschar* )NULL, 0, &attr_size ); AT_OBJECT_ID, ( ntfschar* )NULL, 0, &attr_size );
if (objectid_attr) { if ( objectid_attr )
{
/* restrict to only GUID present in attr */ /* restrict to only GUID present in attr */
if (attr_size == sizeof(GUID)) { if ( attr_size == sizeof( GUID ) )
{
memcpy( &full_objectid.object_id, memcpy( &full_objectid.object_id,
objectid_attr, sizeof( GUID ) ); objectid_attr, sizeof( GUID ) );
full_size = sizeof( GUID ); full_size = sizeof( GUID );
/* get data from index, if any */ /* get data from index, if any */
if ( !merge_index_data( ni, objectid_attr, if ( !merge_index_data( ni, objectid_attr,
&full_objectid)) { &full_objectid ) )
{
full_size = sizeof( OBJECT_ID_ATTR ); full_size = sizeof( OBJECT_ID_ATTR );
} }
if (full_size <= (s64)size) { if ( full_size <= ( s64 )size )
{
if ( value ) if ( value )
memcpy( value, &full_objectid, memcpy( value, &full_objectid,
full_size ); full_size );
else else
errno = EINVAL; errno = EINVAL;
} }
} else { }
else
{
/* unexpected size, better return unsupported */ /* unexpected size, better return unsupported */
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
full_size = 0; full_size = 0;
} }
free( objectid_attr ); free( objectid_attr );
} else }
else
errno = ENODATA; errno = ENODATA;
} }
return ( full_size ? ( int )full_size : -errno ); return ( full_size ? ( int )full_size : -errno );
@ -525,22 +564,28 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni,
int res; int res;
res = 0; res = 0;
if (ni && value && (size >= sizeof(GUID))) { if ( ni && value && ( size >= sizeof( GUID ) ) )
{
xo = open_object_id_index( ni->vol ); xo = open_object_id_index( ni->vol );
if (xo) { if ( xo )
{
/* make sure the GUID was not used somewhere */ /* make sure the GUID was not used somewhere */
memcpy( &key.object_id, value, sizeof( GUID ) ); memcpy( &key.object_id, value, sizeof( GUID ) );
if ( ntfs_index_lookup( &key, if ( ntfs_index_lookup( &key,
sizeof(OBJECT_ID_INDEX_KEY), xo)) { sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
{
ntfs_index_ctx_reinit( xo ); ntfs_index_ctx_reinit( xo );
res = add_object_id( ni, flags ); res = add_object_id( ni, flags );
if (!res) { if ( !res )
{
/* update value and index */ /* update value and index */
res = update_object_id( ni, xo, res = update_object_id( ni, xo,
( const OBJECT_ID_ATTR* )value, ( const OBJECT_ID_ATTR* )value,
size ); size );
} }
} else { }
else
{
/* GUID is present elsewhere */ /* GUID is present elsewhere */
res = -1; res = -1;
errno = EEXIST; errno = EEXIST;
@ -550,10 +595,14 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni,
NInoSetDirty( xoni ); NInoSetDirty( xoni );
ntfs_index_ctx_put( xo ); ntfs_index_ctx_put( xo );
ntfs_inode_close( xoni ); ntfs_inode_close( xoni );
} else { }
else
{
res = -1; res = -1;
} }
} else { }
else
{
errno = EINVAL; errno = EINVAL;
res = -1; res = -1;
} }
@ -577,25 +626,32 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
OBJECT_ID_ATTR old_attr; OBJECT_ID_ATTR old_attr;
res = 0; res = 0;
if (ni) { if ( ni )
{
/* /*
* open and delete the object id * open and delete the object id
*/ */
na = ntfs_attr_open( ni, AT_OBJECT_ID, na = ntfs_attr_open( ni, AT_OBJECT_ID,
AT_UNNAMED, 0 ); AT_UNNAMED, 0 );
if (na) { if ( na )
{
/* first remove index (old object id needed) */ /* first remove index (old object id needed) */
xo = open_object_id_index( ni->vol ); xo = open_object_id_index( ni->vol );
if (xo) { if ( xo )
{
oldsize = remove_object_id_index( na, xo, oldsize = remove_object_id_index( na, xo,
&old_attr ); &old_attr );
if (oldsize < 0) { if ( oldsize < 0 )
{
res = -1; res = -1;
} else { }
else
{
/* now remove attribute */ /* now remove attribute */
res = ntfs_attr_rm( na ); res = ntfs_attr_rm( na );
if ( res if ( res
&& (oldsize > (int)sizeof(GUID))) { && ( oldsize > ( int )sizeof( GUID ) ) )
{
/* /*
* If we could not remove the * If we could not remove the
* attribute, try to restore the * attribute, try to restore the
@ -622,12 +678,16 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
/* avoid errno pollution */ /* avoid errno pollution */
if ( errno == ENOENT ) if ( errno == ENOENT )
errno = olderrno; errno = olderrno;
} else { }
else
{
errno = ENODATA; errno = ENODATA;
res = -1; res = -1;
} }
NInoSetDirty( ni ); NInoSetDirty( ni );
} else { }
else
{
errno = EINVAL; errno = EINVAL;
res = -1; res = -1;
} }

View File

@ -32,7 +32,8 @@
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */ #define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
/* default security sub-authorities */ /* default security sub-authorities */
enum { enum
{
DEFSECAUTH1 = -1153374643, /* 3141592653 */ DEFSECAUTH1 = -1153374643, /* 3141592653 */
DEFSECAUTH2 = 589793238, DEFSECAUTH2 = 589793238,
DEFSECAUTH3 = 462843383, DEFSECAUTH3 = 462843383,

View File

@ -71,7 +71,8 @@
#define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007) #define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007)
#define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C) #define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C)
struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */ struct MOUNT_POINT_REPARSE_DATA /* reparse data for junctions */
{
le16 subst_name_offset; le16 subst_name_offset;
le16 subst_name_length; le16 subst_name_length;
le16 print_name_offset; le16 print_name_offset;
@ -79,7 +80,8 @@ struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */
char path_buffer[0]; /* above data assume this is char array */ char path_buffer[0]; /* above data assume this is char array */
} ; } ;
struct SYMLINK_REPARSE_DATA { /* reparse data for symlinks */ struct SYMLINK_REPARSE_DATA /* reparse data for symlinks */
{
le16 subst_name_offset; le16 subst_name_offset;
le16 subst_name_length; le16 subst_name_length;
le16 print_name_offset; le16 print_name_offset;
@ -88,20 +90,23 @@ struct SYMLINK_REPARSE_DATA { /* reparse data for symlinks */
char path_buffer[0]; /* above data assume this is char array */ char path_buffer[0]; /* above data assume this is char array */
} ; } ;
struct REPARSE_INDEX { /* index entry in $Extend/$Reparse */ struct REPARSE_INDEX /* index entry in $Extend/$Reparse */
{
INDEX_ENTRY_HEADER header; INDEX_ENTRY_HEADER header;
REPARSE_INDEX_KEY key; REPARSE_INDEX_KEY key;
le32 filling; le32 filling;
} ; } ;
static const ntfschar dir_junction_head[] = { static const ntfschar dir_junction_head[] =
{
const_cpu_to_le16( '\\' ), const_cpu_to_le16( '\\' ),
const_cpu_to_le16( '?' ), const_cpu_to_le16( '?' ),
const_cpu_to_le16( '?' ), const_cpu_to_le16( '?' ),
const_cpu_to_le16( '\\' ) const_cpu_to_le16( '\\' )
} ; } ;
static const ntfschar vol_junction_head[] = { static const ntfschar vol_junction_head[] =
{
const_cpu_to_le16( '\\' ), const_cpu_to_le16( '\\' ),
const_cpu_to_le16( '?' ), const_cpu_to_le16( '?' ),
const_cpu_to_le16( '?' ), const_cpu_to_le16( '?' ),
@ -116,7 +121,8 @@ static const ntfschar vol_junction_head[] = {
} ; } ;
static ntfschar reparse_index_name[] = { const_cpu_to_le16( '$' ), static ntfschar reparse_index_name[] = { const_cpu_to_le16( '$' ),
const_cpu_to_le16('R') }; const_cpu_to_le16( 'R' )
};
static const char mappingdir[] = ".NTFS-3G/"; static const char mappingdir[] = ".NTFS-3G/";
@ -146,18 +152,21 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
u32 cpuchar; u32 cpuchar;
INDEX_ENTRY *entry; INDEX_ENTRY *entry;
FILE_NAME_ATTR *found; FILE_NAME_ATTR *found;
struct { struct
{
FILE_NAME_ATTR attr; FILE_NAME_ATTR attr;
ntfschar file_name[NTFS_MAX_NAME_LEN + 1]; ntfschar file_name[NTFS_MAX_NAME_LEN + 1];
} find; } find;
mref = ( u64 ) - 1; /* default return (not found) */ mref = ( u64 ) - 1; /* default return (not found) */
icx = ntfs_index_ctx_get( dir_ni, NTFS_INDEX_I30, 4 ); icx = ntfs_index_ctx_get( dir_ni, NTFS_INDEX_I30, 4 );
if (icx) { if ( icx )
{
if ( uname_len > NTFS_MAX_NAME_LEN ) if ( uname_len > NTFS_MAX_NAME_LEN )
uname_len = NTFS_MAX_NAME_LEN; uname_len = NTFS_MAX_NAME_LEN;
find.attr.file_name_length = uname_len; find.attr.file_name_length = uname_len;
for (i=0; i<uname_len; i++) { for ( i = 0; i < uname_len; i++ )
{
cpuchar = le16_to_cpu( uname[i] ); cpuchar = le16_to_cpu( uname[i] );
/* /*
* We need upper or lower value, whichever is smaller, * We need upper or lower value, whichever is smaller,
@ -184,7 +193,8 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
entry = ntfs_index_next( icx->entry, icx ); entry = ntfs_index_next( icx->entry, icx );
else else
entry = icx->entry; entry = icx->entry;
if (entry) { if ( entry )
{
found = &entry->key.file_name; found = &entry->key.file_name;
if ( lkup if ( lkup
&& ntfs_names_are_equal( find.attr.file_name, && ntfs_names_are_equal( find.attr.file_name,
@ -193,7 +203,8 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
IGNORE_CASE, IGNORE_CASE,
vol->upcase, vol->upcase_len ) ) vol->upcase, vol->upcase_len ) )
lkup = 0; lkup = 0;
if (!lkup) { if ( !lkup )
{
/* /*
* name found : * name found :
* fix original name and return inode * fix original name and return inode
@ -228,9 +239,11 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
target = ( char* )NULL; /* default return */ target = ( char* )NULL; /* default return */
ni = ntfs_inode_open( vol, ( MFT_REF )FILE_root ); ni = ntfs_inode_open( vol, ( MFT_REF )FILE_root );
if (ni) { if ( ni )
{
start = 0; start = 0;
do { do
{
len = 0; len = 0;
while ( ( ( start + len ) < count ) while ( ( ( start + len ) < count )
&& ( path[start + len] != const_cpu_to_le16( '\\' ) ) ) && ( path[start + len] != const_cpu_to_le16( '\\' ) ) )
@ -238,20 +251,24 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
inum = ntfs_fix_file_name( ni, &path[start], len ); inum = ntfs_fix_file_name( ni, &path[start], len );
ntfs_inode_close( ni ); ntfs_inode_close( ni );
ni = ( ntfs_inode* )NULL; ni = ( ntfs_inode* )NULL;
if (inum != (u64)-1) { if ( inum != ( u64 ) - 1 )
{
inum = MREF( inum ); inum = MREF( inum );
ni = ntfs_inode_open( vol, inum ); ni = ntfs_inode_open( vol, inum );
start += len; start += len;
if ( start < count ) if ( start < count )
path[start++] = const_cpu_to_le16( '/' ); path[start++] = const_cpu_to_le16( '/' );
} }
} while (ni }
while ( ni
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) && ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
&& ( start < count ) ); && ( start < count ) );
if ( ni if ( ni
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir ) ) && ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir ) )
if (ntfs_ucstombs(path, count, &target, 0) < 0) { if ( ntfs_ucstombs( path, count, &target, 0 ) < 0 )
if (target) { {
if ( target )
{
free( target ); free( target );
target = ( char* )NULL; target = ( char* )NULL;
} }
@ -288,17 +305,22 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
pos = 0; pos = 0;
ok = TRUE; ok = TRUE;
curni = ntfs_dir_parent_inode( ni ); curni = ntfs_dir_parent_inode( ni );
while (curni && ok && (pos < (count - 1)) && --max) { while ( curni && ok && ( pos < ( count - 1 ) ) && --max )
{
if ( ( count >= ( pos + 2 ) ) if ( ( count >= ( pos + 2 ) )
&& ( path[pos] == const_cpu_to_le16( '.' ) ) && ( path[pos] == const_cpu_to_le16( '.' ) )
&& (path[pos+1] == const_cpu_to_le16('\\'))) { && ( path[pos+1] == const_cpu_to_le16( '\\' ) ) )
{
path[1] = const_cpu_to_le16( '/' ); path[1] = const_cpu_to_le16( '/' );
pos += 2; pos += 2;
} else { }
else
{
if ( ( count >= ( pos + 3 ) ) if ( ( count >= ( pos + 3 ) )
&& ( path[pos] == const_cpu_to_le16( '.' ) ) && ( path[pos] == const_cpu_to_le16( '.' ) )
&& ( path[pos+1] == const_cpu_to_le16( '.' ) ) && ( path[pos+1] == const_cpu_to_le16( '.' ) )
&& (path[pos+2] == const_cpu_to_le16('\\'))) { && ( path[pos+2] == const_cpu_to_le16( '\\' ) ) )
{
path[2] = const_cpu_to_le16( '/' ); path[2] = const_cpu_to_le16( '/' );
pos += 3; pos += 3;
newni = ntfs_dir_parent_inode( curni ); newni = ntfs_dir_parent_inode( curni );
@ -307,7 +329,9 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
curni = newni; curni = newni;
if ( !curni ) if ( !curni )
ok = FALSE; ok = FALSE;
} else { }
else
{
lth = 0; lth = 0;
while ( ( ( pos + lth ) < count ) while ( ( ( pos + lth ) < count )
&& ( path[pos + lth] != const_cpu_to_le16( '\\' ) ) ) && ( path[pos + lth] != const_cpu_to_le16( '\\' ) ) )
@ -321,15 +345,20 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
&& ntfs_inode_close( curni ) ) && ntfs_inode_close( curni ) )
|| ( inum == ( u64 ) - 1 ) ) || ( inum == ( u64 ) - 1 ) )
ok = FALSE; ok = FALSE;
else { else
{
curni = ntfs_inode_open( ni->vol, MREF( inum ) ); curni = ntfs_inode_open( ni->vol, MREF( inum ) );
if ( !curni ) if ( !curni )
ok = FALSE; ok = FALSE;
else { else
if (ok && ((pos + lth) < count)) { {
if ( ok && ( ( pos + lth ) < count ) )
{
path[pos + lth] = const_cpu_to_le16( '/' ); path[pos + lth] = const_cpu_to_le16( '/' );
pos += lth + 1; pos += lth + 1;
} else { }
else
{
pos += lth; pos += lth;
if ( ( ni->mrec->flags ^ curni->mrec->flags ) if ( ( ni->mrec->flags ^ curni->mrec->flags )
& MFT_RECORD_IS_DIRECTORY ) & MFT_RECORD_IS_DIRECTORY )
@ -343,7 +372,8 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
} }
} }
if (ok && (ntfs_ucstombs(path, count, &target, 0) < 0)) { if ( ok && ( ntfs_ucstombs( path, count, &target, 0 ) < 0 ) )
{
free( target ); // needed ? free( target ); // needed ?
target = ( char* )NULL; target = ( char* )NULL;
} }
@ -370,7 +400,8 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
ret = -1; ret = -1;
drive = ( char* )NULL; drive = ( char* )NULL;
sz = ntfs_ucstombs( &letter, 1, &drive, 0 ); sz = ntfs_ucstombs( &letter, 1, &drive, 0 );
if (sz > 0) { if ( sz > 0 )
{
strcpy( defines, mappingdir ); strcpy( defines, mappingdir );
if ( ( *drive >= 'a' ) && ( *drive <= 'z' ) ) if ( ( *drive >= 'a' ) && ( *drive <= 'z' ) )
*drive += 'A' - 'a'; *drive += 'A' - 'a';
@ -380,8 +411,8 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
ni = ntfs_pathname_to_inode( vol, NULL, defines ); ni = ntfs_pathname_to_inode( vol, NULL, defines );
if ( ni && !ntfs_inode_close( ni ) ) if ( ni && !ntfs_inode_close( ni ) )
ret = 1; ret = 1;
else else if ( errno == ENOENT )
if (errno == ENOENT) { {
ret = 0; ret = 0;
/* avoid errno pollution */ /* avoid errno pollution */
errno = olderrno; errno = olderrno;
@ -415,8 +446,10 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
&& ( size >= sizeof( REPARSE_POINT ) ) && ( size >= sizeof( REPARSE_POINT ) )
&& ( ( ( size_t )le16_to_cpu( reparse_attr->reparse_data_length ) && ( ( ( size_t )le16_to_cpu( reparse_attr->reparse_data_length )
+ sizeof( REPARSE_POINT ) ) == size ); + sizeof( REPARSE_POINT ) ) == size );
if (ok) { if ( ok )
switch (reparse_attr->reparse_tag) { {
switch ( reparse_attr->reparse_tag )
{
case IO_REPARSE_TAG_MOUNT_POINT : case IO_REPARSE_TAG_MOUNT_POINT :
mount_point_data = ( const struct MOUNT_POINT_REPARSE_DATA* ) mount_point_data = ( const struct MOUNT_POINT_REPARSE_DATA* )
reparse_attr->reparse_data; reparse_attr->reparse_data;
@ -503,12 +536,15 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
if ( ( kind == DIR_JUNCTION ) if ( ( kind == DIR_JUNCTION )
&& ( count >= 7 ) && ( count >= 7 )
&& junction[7] && junction[7]
&& !ntfs_drive_letter(vol, junction[4])) { && !ntfs_drive_letter( vol, junction[4] ) )
{
target = search_absolute( vol, &junction[7], count - 7, isdir ); target = search_absolute( vol, &junction[7], count - 7, isdir );
if (target) { if ( target )
{
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point ) fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
+ strlen( target ) + 2 ); + strlen( target ) + 2 );
if (fulltarget) { if ( fulltarget )
{
strcpy( fulltarget, mnt_point ); strcpy( fulltarget, mnt_point );
strcat( fulltarget, "/" ); strcat( fulltarget, "/" );
strcat( fulltarget, target ); strcat( fulltarget, target );
@ -523,11 +559,13 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
* define as a symbolic link to the real target * define as a symbolic link to the real target
*/ */
if ( ( ( kind == DIR_JUNCTION ) && !fulltarget ) if ( ( ( kind == DIR_JUNCTION ) && !fulltarget )
|| (kind == VOL_JUNCTION)) { || ( kind == VOL_JUNCTION ) )
{
sz = ntfs_ucstombs( &junction[4], sz = ntfs_ucstombs( &junction[4],
( kind == VOL_JUNCTION ? count - 5 : count - 4 ), ( kind == VOL_JUNCTION ? count - 5 : count - 4 ),
&target, 0 ); &target, 0 );
if ((sz > 0) && target) { if ( ( sz > 0 ) && target )
{
/* reverse slashes */ /* reverse slashes */
for ( q = target; *q; q++ ) for ( q = target; *q; q++ )
if ( *q == '\\' ) if ( *q == '\\' )
@ -539,7 +577,8 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
target[0] += 'A' - 'a'; target[0] += 'A' - 'a';
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point ) fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
+ sizeof( mappingdir ) + strlen( target ) + 1 ); + sizeof( mappingdir ) + strlen( target ) + 1 );
if (fulltarget) { if ( fulltarget )
{
strcpy( fulltarget, mnt_point ); strcpy( fulltarget, mnt_point );
strcat( fulltarget, "/" ); strcat( fulltarget, "/" );
strcat( fulltarget, mappingdir ); strcat( fulltarget, mappingdir );
@ -605,17 +644,20 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
&& ( count >= 3 ) && ( count >= 3 )
&& junction[3] && junction[3]
&& !ntfs_drive_letter( vol, junction[0] ) ) && !ntfs_drive_letter( vol, junction[0] ) )
|| (kind == ABS_PATH)) { || ( kind == ABS_PATH ) )
{
if ( kind == ABS_PATH ) if ( kind == ABS_PATH )
target = search_absolute( vol, &junction[1], target = search_absolute( vol, &junction[1],
count - 1, isdir ); count - 1, isdir );
else else
target = search_absolute( vol, &junction[3], target = search_absolute( vol, &junction[3],
count - 3, isdir ); count - 3, isdir );
if (target) { if ( target )
{
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point ) fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
+ strlen( target ) + 2 ); + strlen( target ) + 2 );
if (fulltarget) { if ( fulltarget )
{
strcpy( fulltarget, mnt_point ); strcpy( fulltarget, mnt_point );
strcat( fulltarget, "/" ); strcat( fulltarget, "/" );
strcat( fulltarget, target ); strcat( fulltarget, target );
@ -628,10 +670,12 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
* link to /.NTFS-3G/target which the user can * link to /.NTFS-3G/target which the user can
* define as a symbolic link to the real target * define as a symbolic link to the real target
*/ */
if ((kind == FULL_PATH) && !fulltarget) { if ( ( kind == FULL_PATH ) && !fulltarget )
{
sz = ntfs_ucstombs( &junction[0], sz = ntfs_ucstombs( &junction[0],
count, &target, 0 ); count, &target, 0 );
if ((sz > 0) && target) { if ( ( sz > 0 ) && target )
{
/* reverse slashes */ /* reverse slashes */
for ( q = target; *q; q++ ) for ( q = target; *q; q++ )
if ( *q == '\\' ) if ( *q == '\\' )
@ -643,7 +687,8 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
target[0] += 'A' - 'a'; target[0] += 'A' - 'a';
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point ) fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
+ sizeof( mappingdir ) + strlen( target ) + 1 ); + sizeof( mappingdir ) + strlen( target ) + 1 );
if (fulltarget) { if ( fulltarget )
{
strcpy( fulltarget, mnt_point ); strcpy( fulltarget, mnt_point );
strcat( fulltarget, "/" ); strcat( fulltarget, "/" );
strcat( fulltarget, mappingdir ); strcat( fulltarget, mappingdir );
@ -710,8 +755,10 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni, reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size ); AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
if ( reparse_attr && attr_size if ( reparse_attr && attr_size
&& valid_reparse_data(ni, reparse_attr, attr_size)) { && valid_reparse_data( ni, reparse_attr, attr_size ) )
switch (reparse_attr->reparse_tag) { {
switch ( reparse_attr->reparse_tag )
{
case IO_REPARSE_TAG_MOUNT_POINT : case IO_REPARSE_TAG_MOUNT_POINT :
mount_point_data = ( struct MOUNT_POINT_REPARSE_DATA* ) mount_point_data = ( struct MOUNT_POINT_REPARSE_DATA* )
reparse_attr->reparse_data; reparse_attr->reparse_data;
@ -734,23 +781,26 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
* Predetermine the kind of target, * Predetermine the kind of target,
* the called function has to make a full check * the called function has to make a full check
*/ */
if (*p++ == const_cpu_to_le16('\\')) { if ( *p++ == const_cpu_to_le16( '\\' ) )
{
if ( ( *p == const_cpu_to_le16( '?' ) ) if ( ( *p == const_cpu_to_le16( '?' ) )
|| ( *p == const_cpu_to_le16( '\\' ) ) ) || ( *p == const_cpu_to_le16( '\\' ) ) )
kind = FULL_TARGET; kind = FULL_TARGET;
else else
kind = ABS_TARGET; kind = ABS_TARGET;
} else }
if (*p == const_cpu_to_le16(':')) else if ( *p == const_cpu_to_le16( ':' ) )
kind = ABS_TARGET; kind = ABS_TARGET;
else else
kind = REL_TARGET; kind = REL_TARGET;
p--; p--;
/* reparse data consistency has been checked */ /* reparse data consistency has been checked */
switch (kind) { switch ( kind )
{
case FULL_TARGET : case FULL_TARGET :
if ( !( symlink_data->flags if ( !( symlink_data->flags
& const_cpu_to_le32(1))) { & const_cpu_to_le32( 1 ) ) )
{
target = ntfs_get_fulllink( vol, target = ntfs_get_fulllink( vol,
p, lth / 2, p, lth / 2,
mnt_point, isdir ); mnt_point, isdir );
@ -760,7 +810,8 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
break; break;
case ABS_TARGET : case ABS_TARGET :
if ( symlink_data->flags if ( symlink_data->flags
& const_cpu_to_le32(1)) { & const_cpu_to_le32( 1 ) )
{
target = ntfs_get_abslink( vol, target = ntfs_get_abslink( vol,
p, lth / 2, p, lth / 2,
mnt_point, isdir ); mnt_point, isdir );
@ -770,7 +821,8 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
break; break;
case REL_TARGET : case REL_TARGET :
if ( symlink_data->flags if ( symlink_data->flags
& const_cpu_to_le32(1)) { & const_cpu_to_le32( 1 ) )
{
target = ntfs_get_rellink( ni, target = ntfs_get_rellink( ni,
p, lth / 2 ); p, lth / 2 );
if ( target ) if ( target )
@ -805,8 +857,10 @@ BOOL ntfs_possible_symlink(ntfs_inode *ni)
possible = FALSE; possible = FALSE;
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni, reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size ); AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
if (reparse_attr && attr_size) { if ( reparse_attr && attr_size )
switch (reparse_attr->reparse_tag) { {
switch ( reparse_attr->reparse_tag )
{
case IO_REPARSE_TAG_MOUNT_POINT : case IO_REPARSE_TAG_MOUNT_POINT :
case IO_REPARSE_TAG_SYMLINK : case IO_REPARSE_TAG_SYMLINK :
possible = TRUE; possible = TRUE;
@ -877,10 +931,12 @@ static int remove_reparse_index(ntfs_attr *na, ntfs_index_context *xr,
int ret; int ret;
ret = na->data_size; ret = na->data_size;
if (ret) { if ( ret )
{
/* read the existing reparse_tag */ /* read the existing reparse_tag */
size = ntfs_attr_pread( na, 0, 4, preparse_tag ); size = ntfs_attr_pread( na, 0, 4, preparse_tag );
if (size == 4) { if ( size == 4 )
{
seqn = na->ni->mrec->sequence_number; seqn = na->ni->mrec->sequence_number;
file_id_cpu = MK_MREF( na->ni->mft_no, le16_to_cpu( seqn ) ); file_id_cpu = MK_MREF( na->ni->mft_no, le16_to_cpu( seqn ) );
file_id = cpu_to_le64( file_id_cpu ); file_id = cpu_to_le64( file_id_cpu );
@ -890,7 +946,9 @@ static int remove_reparse_index(ntfs_attr *na, ntfs_index_context *xr,
if ( !ntfs_index_lookup( &key, sizeof( REPARSE_INDEX_KEY ), xr ) if ( !ntfs_index_lookup( &key, sizeof( REPARSE_INDEX_KEY ), xr )
&& ntfs_index_rm( xr ) ) && ntfs_index_rm( xr ) )
ret = -1; ret = -1;
} else { }
else
{
ret = -1; ret = -1;
errno = ENODATA; errno = ENODATA;
} }
@ -917,18 +975,22 @@ static ntfs_index_context *open_reparse_index(ntfs_volume *vol)
/* do not use path_name_to inode - could reopen root */ /* do not use path_name_to inode - could reopen root */
dir_ni = ntfs_inode_open( vol, FILE_Extend ); dir_ni = ntfs_inode_open( vol, FILE_Extend );
ni = ( ntfs_inode* )NULL; ni = ( ntfs_inode* )NULL;
if (dir_ni) { if ( dir_ni )
{
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$Reparse" ); inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$Reparse" );
if ( inum != ( u64 ) - 1 ) if ( inum != ( u64 ) - 1 )
ni = ntfs_inode_open( vol, inum ); ni = ntfs_inode_open( vol, inum );
ntfs_inode_close( dir_ni ); ntfs_inode_close( dir_ni );
} }
if (ni) { if ( ni )
{
xr = ntfs_index_ctx_get( ni, reparse_index_name, 2 ); xr = ntfs_index_ctx_get( ni, reparse_index_name, 2 );
if (!xr) { if ( !xr )
{
ntfs_inode_close( ni ); ntfs_inode_close( ni );
} }
} else }
else
xr = ( ntfs_index_context* )NULL; xr = ( ntfs_index_context* )NULL;
return ( xr ); return ( xr );
} }
@ -959,19 +1021,23 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
res = 0; res = 0;
na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 ); na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 );
if (na) { if ( na )
{
/* remove the existing reparse data */ /* remove the existing reparse data */
oldsize = remove_reparse_index( na, xr, &reparse_tag ); oldsize = remove_reparse_index( na, xr, &reparse_tag );
if ( oldsize < 0 ) if ( oldsize < 0 )
res = -1; res = -1;
else { else
{
/* resize attribute */ /* resize attribute */
res = ntfs_attr_truncate( na, ( s64 )size ); res = ntfs_attr_truncate( na, ( s64 )size );
/* overwrite value if any */ /* overwrite value if any */
if (!res && value) { if ( !res && value )
{
written = ( int )ntfs_attr_pwrite( na, written = ( int )ntfs_attr_pwrite( na,
( s64 )0, ( s64 )size, value ); ( s64 )0, ( s64 )size, value );
if (written != (s64)size) { if ( written != ( s64 )size )
{
ntfs_log_error( "Failed to update " ntfs_log_error( "Failed to update "
"reparse data\n" ); "reparse data\n" );
errno = EIO; errno = EIO;
@ -981,7 +1047,8 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
if ( !res if ( !res
&& set_reparse_index( ni, xr, && set_reparse_index( ni, xr,
( ( const REPARSE_POINT* )value )->reparse_tag ) ( ( const REPARSE_POINT* )value )->reparse_tag )
&& (oldsize > 0)) { && ( oldsize > 0 ) )
{
/* /*
* If cannot index, try to remove the reparse * If cannot index, try to remove the reparse
* data and log the error. There will be an * data and log the error. There will be an
@ -994,7 +1061,8 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
} }
ntfs_attr_close( na ); ntfs_attr_close( na );
NInoSetDirty( ni ); NInoSetDirty( ni );
} else }
else
res = -1; res = -1;
return ( res ); return ( res );
} }
@ -1018,13 +1086,15 @@ int ntfs_delete_reparse_index(ntfs_inode *ni)
res = 0; res = 0;
na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 ); na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 );
if (na) { if ( na )
{
/* /*
* read the existing reparse data (the tag is enough) * read the existing reparse data (the tag is enough)
* and un-index it * and un-index it
*/ */
xr = open_reparse_index( ni->vol ); xr = open_reparse_index( ni->vol );
if (xr) { if ( xr )
{
if ( remove_reparse_index( na, xr, &reparse_tag ) < 0 ) if ( remove_reparse_index( na, xr, &reparse_tag ) < 0 )
res = -1; res = -1;
xrni = xr->ni; xrni = xr->ni;
@ -1053,12 +1123,16 @@ int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size)
s64 attr_size; s64 attr_size;
attr_size = 0; /* default to no data and no error */ attr_size = 0; /* default to no data and no error */
if (ni) { if ( ni )
if (ni->flags & FILE_ATTR_REPARSE_POINT) { {
if ( ni->flags & FILE_ATTR_REPARSE_POINT )
{
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni, reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size ); AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
if (reparse_attr) { if ( reparse_attr )
if (attr_size <= (s64)size) { {
if ( attr_size <= ( s64 )size )
{
if ( value ) if ( value )
memcpy( value, reparse_attr, memcpy( value, reparse_attr,
attr_size ); attr_size );
@ -1067,7 +1141,8 @@ int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size)
} }
free( reparse_attr ); free( reparse_attr );
} }
} else }
else
errno = ENODATA; errno = ENODATA;
} }
return ( attr_size ? ( int )attr_size : -errno ); return ( attr_size ? ( int )attr_size : -errno );
@ -1090,43 +1165,57 @@ int ntfs_set_ntfs_reparse_data(ntfs_inode *ni,
ntfs_index_context *xr; ntfs_index_context *xr;
res = 0; res = 0;
if (ni && valid_reparse_data(ni, (const REPARSE_POINT*)value, size)) { if ( ni && valid_reparse_data( ni, ( const REPARSE_POINT* )value, size ) )
{
xr = open_reparse_index( ni->vol ); xr = open_reparse_index( ni->vol );
if (xr) { if ( xr )
{
if ( !ntfs_attr_exist( ni, AT_REPARSE_POINT, if ( !ntfs_attr_exist( ni, AT_REPARSE_POINT,
AT_UNNAMED,0)) { AT_UNNAMED, 0 ) )
if (!(flags & XATTR_REPLACE)) { {
if ( !( flags & XATTR_REPLACE ) )
{
/* /*
* no reparse data attribute : add one, * no reparse data attribute : add one,
* apparently, this does not feed the new value in * apparently, this does not feed the new value in
* Note : NTFS version must be >= 3 * Note : NTFS version must be >= 3
*/ */
if (ni->vol->major_ver >= 3) { if ( ni->vol->major_ver >= 3 )
{
res = ntfs_attr_add( ni, res = ntfs_attr_add( ni,
AT_REPARSE_POINT, AT_REPARSE_POINT,
AT_UNNAMED, 0, &dummy, AT_UNNAMED, 0, &dummy,
( s64 )0 ); ( s64 )0 );
if (!res) { if ( !res )
{
ni->flags |= ni->flags |=
FILE_ATTR_REPARSE_POINT; FILE_ATTR_REPARSE_POINT;
NInoFileNameSetDirty( ni ); NInoFileNameSetDirty( ni );
} }
NInoSetDirty( ni ); NInoSetDirty( ni );
} else { }
else
{
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
res = -1; res = -1;
} }
} else { }
else
{
errno = ENODATA; errno = ENODATA;
res = -1; res = -1;
} }
} else { }
if (flags & XATTR_CREATE) { else
{
if ( flags & XATTR_CREATE )
{
errno = EEXIST; errno = EEXIST;
res = -1; res = -1;
} }
} }
if (!res) { if ( !res )
{
/* update value and index */ /* update value and index */
res = update_reparse_data( ni, xr, value, size ); res = update_reparse_data( ni, xr, value, size );
} }
@ -1135,10 +1224,14 @@ int ntfs_set_ntfs_reparse_data(ntfs_inode *ni,
NInoSetDirty( xrni ); NInoSetDirty( xrni );
ntfs_index_ctx_put( xr ); ntfs_index_ctx_put( xr );
ntfs_inode_close( xrni ); ntfs_inode_close( xrni );
} else { }
else
{
res = -1; res = -1;
} }
} else { }
else
{
errno = EINVAL; errno = EINVAL;
res = -1; res = -1;
} }
@ -1161,27 +1254,36 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
le32 reparse_tag; le32 reparse_tag;
res = 0; res = 0;
if (ni) { if ( ni )
{
/* /*
* open and delete the reparse data * open and delete the reparse data
*/ */
na = ntfs_attr_open( ni, AT_REPARSE_POINT, na = ntfs_attr_open( ni, AT_REPARSE_POINT,
AT_UNNAMED, 0 ); AT_UNNAMED, 0 );
if (na) { if ( na )
{
/* first remove index (reparse data needed) */ /* first remove index (reparse data needed) */
xr = open_reparse_index( ni->vol ); xr = open_reparse_index( ni->vol );
if (xr) { if ( xr )
{
if ( remove_reparse_index( na, xr, if ( remove_reparse_index( na, xr,
&reparse_tag) < 0) { &reparse_tag ) < 0 )
{
res = -1; res = -1;
} else { }
else
{
/* now remove attribute */ /* now remove attribute */
res = ntfs_attr_rm( na ); res = ntfs_attr_rm( na );
if (!res) { if ( !res )
{
ni->flags &= ni->flags &=
~FILE_ATTR_REPARSE_POINT; ~FILE_ATTR_REPARSE_POINT;
NInoFileNameSetDirty( ni ); NInoFileNameSetDirty( ni );
} else { }
else
{
/* /*
* If we could not remove the * If we could not remove the
* attribute, try to restore the * attribute, try to restore the
@ -1207,12 +1309,16 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
/* avoid errno pollution */ /* avoid errno pollution */
if ( errno == ENOENT ) if ( errno == ENOENT )
errno = olderrno; errno = olderrno;
} else { }
else
{
errno = ENODATA; errno = ENODATA;
res = -1; res = -1;
} }
NInoSetDirty( ni ); NInoSetDirty( ni );
} else { }
else
{
errno = EINVAL; errno = EINVAL;
res = -1; res = -1;
} }

View File

@ -127,19 +127,24 @@ runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
int last; int last;
int irl; int irl;
if (na->rl && rl) { if ( na->rl && rl )
{
irl = ( int )( rl - na->rl ); irl = ( int )( rl - na->rl );
last = irl; last = irl;
while ( na->rl[last].length ) while ( na->rl[last].length )
last++; last++;
newrl = ntfs_rl_realloc( na->rl, last + 1, last + more_entries + 1 ); newrl = ntfs_rl_realloc( na->rl, last + 1, last + more_entries + 1 );
if (!newrl) { if ( !newrl )
{
errno = ENOMEM; errno = ENOMEM;
rl = ( runlist_element* )NULL; rl = ( runlist_element* )NULL;
} else }
else
na->rl = newrl; na->rl = newrl;
rl = &newrl[irl]; rl = &newrl[irl];
} else { }
else
{
ntfs_log_error( "Cannot extend unmapped runlist" ); ntfs_log_error( "Cannot extend unmapped runlist" );
errno = EIO; errno = EIO;
rl = ( runlist_element* )NULL; rl = ( runlist_element* )NULL;
@ -160,7 +165,8 @@ runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
*/ */
static BOOL ntfs_rl_are_mergeable( runlist_element *dst, runlist_element *src ) static BOOL ntfs_rl_are_mergeable( runlist_element *dst, runlist_element *src )
{ {
if (!dst || !src) { if ( !dst || !src )
{
ntfs_log_debug( "Eeek. ntfs_rl_are_mergeable() invoked with NULL " ntfs_log_debug( "Eeek. ntfs_rl_are_mergeable() invoked with NULL "
"pointer!\n" ); "pointer!\n" );
return FALSE; return FALSE;
@ -223,7 +229,8 @@ static runlist_element *ntfs_rl_append(runlist_element *dst, int dsize,
BOOL right = FALSE; /* Right end of @src needs merging */ BOOL right = FALSE; /* Right end of @src needs merging */
int marker; /* End of the inserted runs */ int marker; /* End of the inserted runs */
if (!dst || !src) { if ( !dst || !src )
{
ntfs_log_debug( "Eeek. ntfs_rl_append() invoked with NULL " ntfs_log_debug( "Eeek. ntfs_rl_append() invoked with NULL "
"pointer!\n" ); "pointer!\n" );
errno = EINVAL; errno = EINVAL;
@ -291,7 +298,8 @@ static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize,
BOOL disc = FALSE; /* Discontinuity between @dst and @src */ BOOL disc = FALSE; /* Discontinuity between @dst and @src */
int marker; /* End of the inserted runs */ int marker; /* End of the inserted runs */
if (!dst || !src) { if ( !dst || !src )
{
ntfs_log_debug( "Eeek. ntfs_rl_insert() invoked with NULL " ntfs_log_debug( "Eeek. ntfs_rl_insert() invoked with NULL "
"pointer!\n" ); "pointer!\n" );
errno = EINVAL; errno = EINVAL;
@ -303,7 +311,8 @@ static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize,
*/ */
if ( loc == 0 ) if ( loc == 0 )
disc = ( src[0].vcn > 0 ); disc = ( src[0].vcn > 0 );
else { else
{
s64 merged_length; s64 merged_length;
left = ntfs_rl_are_mergeable( dst + loc - 1, src ); left = ntfs_rl_are_mergeable( dst + loc - 1, src );
@ -348,11 +357,15 @@ static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize,
dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn; dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn;
/* Writing beyond the end of the file and there's a discontinuity. */ /* Writing beyond the end of the file and there's a discontinuity. */
if (disc) { if ( disc )
if (loc > 0) { {
if ( loc > 0 )
{
dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length; dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length;
dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
} else { }
else
{
dst[loc].vcn = 0; dst[loc].vcn = 0;
dst[loc].length = dst[loc + 1].vcn; dst[loc].length = dst[loc + 1].vcn;
} }
@ -390,7 +403,8 @@ static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize,
int tail; /* Start of tail of @dst */ int tail; /* Start of tail of @dst */
int marker; /* End of the inserted runs */ int marker; /* End of the inserted runs */
if (!dst || !src) { if ( !dst || !src )
{
ntfs_log_debug( "Eeek. ntfs_rl_replace() invoked with NULL " ntfs_log_debug( "Eeek. ntfs_rl_replace() invoked with NULL "
"pointer!\n" ); "pointer!\n" );
errno = EINVAL; errno = EINVAL;
@ -407,7 +421,8 @@ static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize,
* ends get merged. The -1 accounts for the run being replaced. * ends get merged. The -1 accounts for the run being replaced.
*/ */
delta = ssize - 1 - left - right; delta = ssize - 1 - left - right;
if (delta > 0) { if ( delta > 0 )
{
dst = ntfs_rl_realloc( dst, dsize, dsize + delta ); dst = ntfs_rl_realloc( dst, dsize, dsize + delta );
if ( !dst ) if ( !dst )
return NULL; return NULL;
@ -471,7 +486,8 @@ static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize,
static runlist_element *ntfs_rl_split( runlist_element *dst, int dsize, static runlist_element *ntfs_rl_split( runlist_element *dst, int dsize,
runlist_element *src, int ssize, int loc ) runlist_element *src, int ssize, int loc )
{ {
if (!dst || !src) { if ( !dst || !src )
{
ntfs_log_debug( "Eeek. ntfs_rl_split() invoked with NULL pointer!\n" ); ntfs_log_debug( "Eeek. ntfs_rl_split() invoked with NULL pointer!\n" );
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
@ -524,10 +540,12 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
return drl; return drl;
/* Check for the case where the first mapping is being done now. */ /* Check for the case where the first mapping is being done now. */
if (!drl) { if ( !drl )
{
drl = srl; drl = srl;
/* Complete the source runlist if necessary. */ /* Complete the source runlist if necessary. */
if (drl[0].vcn) { if ( drl[0].vcn )
{
/* Scan to the end of the source runlist. */ /* Scan to the end of the source runlist. */
for ( dend = 0; drl[dend].length; dend++ ) for ( dend = 0; drl[dend].length; dend++ )
; ;
@ -551,7 +569,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
si++; si++;
/* Can't have an entirely unmapped source runlist. */ /* Can't have an entirely unmapped source runlist. */
if (!srl[si].length) { if ( !srl[si].length )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: unmapped source runlist", __FUNCTION__ ); ntfs_log_perror( "%s: unmapped source runlist", __FUNCTION__ );
return NULL; return NULL;
@ -565,7 +584,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
* be inserted. If we reach the end of @drl, @srl just needs to be * be inserted. If we reach the end of @drl, @srl just needs to be
* appended to @drl. * appended to @drl.
*/ */
for (; drl[di].length; di++) { for ( ; drl[di].length; di++ )
{
if ( drl[di].vcn + drl[di].length > srl[sstart].vcn ) if ( drl[di].vcn + drl[di].length > srl[sstart].vcn )
break; break;
} }
@ -573,7 +593,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
/* Sanity check for illegal overlaps. */ /* Sanity check for illegal overlaps. */
if ( ( drl[di].vcn == srl[si].vcn ) && ( drl[di].lcn >= 0 ) && if ( ( drl[di].vcn == srl[si].vcn ) && ( drl[di].lcn >= 0 ) &&
(srl[si].lcn >= 0)) { ( srl[si].lcn >= 0 ) )
{
errno = ERANGE; errno = ERANGE;
ntfs_log_perror( "Run lists overlap. Cannot merge" ); ntfs_log_perror( "Run lists overlap. Cannot merge" );
return NULL; return NULL;
@ -617,31 +638,38 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
ntfs_log_debug( "start = %i, finish = %i\n", start, finish ); ntfs_log_debug( "start = %i, finish = %i\n", start, finish );
ntfs_log_debug( "ds = %i, ss = %i, dins = %i\n", ds, ss, dins ); ntfs_log_debug( "ds = %i, ss = %i, dins = %i\n", ds, ss, dins );
if (start) { if ( start )
{
if ( finish ) if ( finish )
drl = ntfs_rl_replace( drl, ds, srl + sstart, ss, dins ); drl = ntfs_rl_replace( drl, ds, srl + sstart, ss, dins );
else else
drl = ntfs_rl_insert( drl, ds, srl + sstart, ss, dins ); drl = ntfs_rl_insert( drl, ds, srl + sstart, ss, dins );
} else { }
else
{
if ( finish ) if ( finish )
drl = ntfs_rl_append( drl, ds, srl + sstart, ss, dins ); drl = ntfs_rl_append( drl, ds, srl + sstart, ss, dins );
else else
drl = ntfs_rl_split( drl, ds, srl + sstart, ss, dins ); drl = ntfs_rl_split( drl, ds, srl + sstart, ss, dins );
} }
if (!drl) { if ( !drl )
{
ntfs_log_perror( "Merge failed" ); ntfs_log_perror( "Merge failed" );
return drl; return drl;
} }
free( srl ); free( srl );
if (marker) { if ( marker )
{
ntfs_log_debug( "Triggering marker code.\n" ); ntfs_log_debug( "Triggering marker code.\n" );
for ( ds = dend; drl[ds].length; ds++ ) for ( ds = dend; drl[ds].length; ds++ )
; ;
/* We only need to care if @srl ended after @drl. */ /* We only need to care if @srl ended after @drl. */
if (drl[ds].vcn <= marker_vcn) { if ( drl[ds].vcn <= marker_vcn )
{
int slots = 0; int slots = 0;
if (drl[ds].vcn == marker_vcn) { if ( drl[ds].vcn == marker_vcn )
{
ntfs_log_debug( "Old marker = %lli, replacing with " ntfs_log_debug( "Old marker = %lli, replacing with "
"LCN_ENOENT.\n", "LCN_ENOENT.\n",
( long long )drl[ds].lcn ); ( long long )drl[ds].lcn );
@ -653,13 +681,16 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
* @drl or extend an existing one before adding the * @drl or extend an existing one before adding the
* ENOENT terminator. * ENOENT terminator.
*/ */
if (drl[ds].lcn == (LCN)LCN_ENOENT) { if ( drl[ds].lcn == ( LCN )LCN_ENOENT )
{
ds--; ds--;
slots = 1; slots = 1;
} }
if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) { if ( drl[ds].lcn != ( LCN )LCN_RL_NOT_MAPPED )
{
/* Add an unmapped runlist element. */ /* Add an unmapped runlist element. */
if (!slots) { if ( !slots )
{
/* FIXME/TODO: We need to have the /* FIXME/TODO: We need to have the
* extra memory already! (AIA) * extra memory already! (AIA)
*/ */
@ -680,7 +711,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
drl[ds].length = marker_vcn - drl[ds].vcn; drl[ds].length = marker_vcn - drl[ds].vcn;
/* Finally add the ENOENT terminator. */ /* Finally add the ENOENT terminator. */
ds++; ds++;
if (!slots) { if ( !slots )
{
/* FIXME/TODO: We need to have the extra /* FIXME/TODO: We need to have the extra
* memory already! (AIA) * memory already! (AIA)
*/ */
@ -797,7 +829,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
( unsigned )le32_to_cpu( attr->type ) ); ( unsigned )le32_to_cpu( attr->type ) );
/* Make sure attr exists and is non-resident. */ /* Make sure attr exists and is non-resident. */
if ( !attr || !attr->non_resident || if ( !attr || !attr->non_resident ||
sle64_to_cpu(attr->lowest_vcn) < (VCN)0) { sle64_to_cpu( attr->lowest_vcn ) < ( VCN )0 )
{
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
@ -807,7 +840,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
/* Get start of the mapping pairs array. */ /* Get start of the mapping pairs array. */
buf = ( const u8* )attr + le16_to_cpu( attr->mapping_pairs_offset ); buf = ( const u8* )attr + le16_to_cpu( attr->mapping_pairs_offset );
attr_end = ( const u8* )attr + le32_to_cpu( attr->length ); attr_end = ( const u8* )attr + le32_to_cpu( attr->length );
if (buf < (const u8*)attr || buf > attr_end) { if ( buf < ( const u8* )attr || buf > attr_end )
{
ntfs_log_debug( "Corrupt attribute.\n" ); ntfs_log_debug( "Corrupt attribute.\n" );
errno = EIO; errno = EIO;
return NULL; return NULL;
@ -820,23 +854,27 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
if ( !rl ) if ( !rl )
return NULL; return NULL;
/* Insert unmapped starting element if necessary. */ /* Insert unmapped starting element if necessary. */
if (vcn) { if ( vcn )
{
rl->vcn = ( VCN )0; rl->vcn = ( VCN )0;
rl->lcn = ( LCN )LCN_RL_NOT_MAPPED; rl->lcn = ( LCN )LCN_RL_NOT_MAPPED;
rl->length = vcn; rl->length = vcn;
rlpos++; rlpos++;
} }
while (buf < attr_end && *buf) { while ( buf < attr_end && *buf )
{
/* /*
* Allocate more memory if needed, including space for the * Allocate more memory if needed, including space for the
* not-mapped and terminator elements. * not-mapped and terminator elements.
*/ */
if ((int)((rlpos + 3) * sizeof(*old_rl)) > rlsize) { if ( ( int )( ( rlpos + 3 ) * sizeof( *old_rl ) ) > rlsize )
{
runlist_element *rl2; runlist_element *rl2;
rlsize += 0x1000; rlsize += 0x1000;
rl2 = realloc( rl, rlsize ); rl2 = realloc( rl, rlsize );
if (!rl2) { if ( !rl2 )
{
int eo = errno; int eo = errno;
free( rl ); free( rl );
errno = eo; errno = eo;
@ -854,12 +892,15 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
* length as a signed value so that's how it is... * length as a signed value so that's how it is...
*/ */
b = *buf & 0xf; b = *buf & 0xf;
if (b) { if ( b )
{
if ( buf + b > attr_end ) if ( buf + b > attr_end )
goto io_error; goto io_error;
for ( deltaxcn = ( s8 )buf[b--]; b; b-- ) for ( deltaxcn = ( s8 )buf[b--]; b; b-- )
deltaxcn = ( deltaxcn << 8 ) + buf[b]; deltaxcn = ( deltaxcn << 8 ) + buf[b];
} else { /* The length entry is compulsory. */ }
else /* The length entry is compulsory. */
{
ntfs_log_debug( "Missing length entry in mapping pairs " ntfs_log_debug( "Missing length entry in mapping pairs "
"array.\n" ); "array.\n" );
deltaxcn = ( s64 ) - 1; deltaxcn = ( s64 ) - 1;
@ -868,7 +909,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
* Assume a negative length to indicate data corruption and * Assume a negative length to indicate data corruption and
* hence clean-up and return NULL. * hence clean-up and return NULL.
*/ */
if (deltaxcn < 0) { if ( deltaxcn < 0 )
{
ntfs_log_debug( "Invalid length in mapping pairs array.\n" ); ntfs_log_debug( "Invalid length in mapping pairs array.\n" );
goto err_out; goto err_out;
} }
@ -886,7 +928,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
*/ */
if ( !( *buf & 0xf0 ) ) if ( !( *buf & 0xf0 ) )
rl[rlpos].lcn = ( LCN )LCN_HOLE; rl[rlpos].lcn = ( LCN )LCN_HOLE;
else { else
{
/* Get the lcn change which really can be negative. */ /* Get the lcn change which really can be negative. */
u8 b2 = *buf & 0xf; u8 b2 = *buf & 0xf;
b = b2 + ( ( *buf >> 4 ) & 0xf ); b = b2 + ( ( *buf >> 4 ) & 0xf );
@ -904,7 +947,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
* -1. So if either is found give us a message so we * -1. So if either is found give us a message so we
* can investigate it further! * can investigate it further!
*/ */
if (vol->major_ver < 3) { if ( vol->major_ver < 3 )
{
if ( deltaxcn == ( LCN ) - 1 ) if ( deltaxcn == ( LCN ) - 1 )
ntfs_log_debug( "lcn delta == -1\n" ); ntfs_log_debug( "lcn delta == -1\n" );
if ( lcn == ( LCN ) - 1 ) if ( lcn == ( LCN ) - 1 )
@ -912,7 +956,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
} }
#endif #endif
/* Check lcn is not below -1. */ /* Check lcn is not below -1. */
if (lcn < (LCN)-1) { if ( lcn < ( LCN ) - 1 )
{
ntfs_log_debug( "Invalid LCN < -1 in mapping pairs " ntfs_log_debug( "Invalid LCN < -1 in mapping pairs "
"array.\n" ); "array.\n" );
goto err_out; goto err_out;
@ -932,14 +977,16 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
* vcn in the runlist - 1, or something has gone badly wrong. * vcn in the runlist - 1, or something has gone badly wrong.
*/ */
deltaxcn = sle64_to_cpu( attr->highest_vcn ); deltaxcn = sle64_to_cpu( attr->highest_vcn );
if (deltaxcn && vcn - 1 != deltaxcn) { if ( deltaxcn && vcn - 1 != deltaxcn )
{
mpa_err: mpa_err:
ntfs_log_debug( "Corrupt mapping pairs array in non-resident " ntfs_log_debug( "Corrupt mapping pairs array in non-resident "
"attribute.\n" ); "attribute.\n" );
goto err_out; goto err_out;
} }
/* Setup not mapped runlist element if this is the base extent. */ /* Setup not mapped runlist element if this is the base extent. */
if (!attr->lowest_vcn) { if ( !attr->lowest_vcn )
{
VCN max_cluster; VCN max_cluster;
max_cluster = ( ( sle64_to_cpu( attr->allocated_size ) + max_cluster = ( ( sle64_to_cpu( attr->allocated_size ) +
@ -949,14 +996,16 @@ mpa_err:
* A highest_vcn of zero means this is a single extent * A highest_vcn of zero means this is a single extent
* attribute so simply terminate the runlist with LCN_ENOENT). * attribute so simply terminate the runlist with LCN_ENOENT).
*/ */
if (deltaxcn) { if ( deltaxcn )
{
/* /*
* If there is a difference between the highest_vcn and * If there is a difference between the highest_vcn and
* the highest cluster, the runlist is either corrupt * the highest cluster, the runlist is either corrupt
* or, more likely, there are more extents following * or, more likely, there are more extents following
* this one. * this one.
*/ */
if (deltaxcn < max_cluster) { if ( deltaxcn < max_cluster )
{
ntfs_log_debug( "More extents to follow; deltaxcn = " ntfs_log_debug( "More extents to follow; deltaxcn = "
"0x%llx, max_cluster = 0x%llx\n", "0x%llx, max_cluster = 0x%llx\n",
( long long )deltaxcn, ( long long )deltaxcn,
@ -965,7 +1014,9 @@ mpa_err:
vcn += rl[rlpos].length = max_cluster - deltaxcn; vcn += rl[rlpos].length = max_cluster - deltaxcn;
rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED; rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED;
rlpos++; rlpos++;
} else if (deltaxcn > max_cluster) { }
else if ( deltaxcn > max_cluster )
{
ntfs_log_debug( "Corrupt attribute. deltaxcn = " ntfs_log_debug( "Corrupt attribute. deltaxcn = "
"0x%llx, max_cluster = 0x%llx\n", "0x%llx, max_cluster = 0x%llx\n",
( long long )deltaxcn, ( long long )deltaxcn,
@ -974,14 +1025,16 @@ mpa_err:
} }
} }
rl[rlpos].lcn = ( LCN )LCN_ENOENT; rl[rlpos].lcn = ( LCN )LCN_ENOENT;
} else /* Not the base extent. There may be more extents to follow. */ }
else /* Not the base extent. There may be more extents to follow. */
rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED; rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED;
/* Setup terminating runlist element. */ /* Setup terminating runlist element. */
rl[rlpos].vcn = vcn; rl[rlpos].vcn = vcn;
rl[rlpos].length = ( s64 )0; rl[rlpos].length = ( s64 )0;
/* If no existing runlist was specified, we are done. */ /* If no existing runlist was specified, we are done. */
if (!old_rl) { if ( !old_rl )
{
ntfs_log_debug( "Mapping pairs array successfully decompressed:\n" ); ntfs_log_debug( "Mapping pairs array successfully decompressed:\n" );
ntfs_debug_runlist_dump( rl ); ntfs_debug_runlist_dump( rl );
return rl; return rl;
@ -1051,8 +1104,10 @@ LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
if ( vcn < rl[0].vcn ) if ( vcn < rl[0].vcn )
return ( LCN )LCN_ENOENT; return ( LCN )LCN_ENOENT;
for (i = 0; rl[i].length; i++) { for ( i = 0; rl[i].length; i++ )
if (vcn < rl[i+1].vcn) { {
if ( vcn < rl[i+1].vcn )
{
if ( rl[i].lcn >= ( LCN )0 ) if ( rl[i].lcn >= ( LCN )0 )
return rl[i].lcn + ( vcn - rl[i].vcn ); return rl[i].lcn + ( vcn - rl[i].vcn );
return rl[i].lcn; return rl[i].lcn;
@ -1098,7 +1153,8 @@ s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
s64 bytes_read, to_read, ofs, total; s64 bytes_read, to_read, ofs, total;
int err = EIO; int err = EIO;
if (!vol || !rl || pos < 0 || count < 0) { if ( !vol || !rl || pos < 0 || count < 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "Failed to read runlist [vol: %p rl: %p " ntfs_log_perror( "Failed to read runlist [vol: %p rl: %p "
"pos: %lld count: %lld]", vol, rl, "pos: %lld count: %lld]", vol, rl,
@ -1113,10 +1169,12 @@ s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
ofs += ( rl->length << vol->cluster_size_bits ); ofs += ( rl->length << vol->cluster_size_bits );
/* Offset in the run at which to begin reading. */ /* Offset in the run at which to begin reading. */
ofs = pos - ofs; ofs = pos - ofs;
for (total = 0LL; count; rl++, ofs = 0) { for ( total = 0LL; count; rl++, ofs = 0 )
{
if ( !rl->length ) if ( !rl->length )
goto rl_err_out; goto rl_err_out;
if (rl->lcn < (LCN)0) { if ( rl->lcn < ( LCN )0 )
{
if ( rl->lcn != ( LCN )LCN_HOLE ) if ( rl->lcn != ( LCN )LCN_HOLE )
goto rl_err_out; goto rl_err_out;
/* It is a hole. Just fill buffer @b with zeroes. */ /* It is a hole. Just fill buffer @b with zeroes. */
@ -1136,7 +1194,8 @@ retry:
bytes_read = ntfs_pread( vol->dev, ( rl->lcn << bytes_read = ntfs_pread( vol->dev, ( rl->lcn <<
vol->cluster_size_bits ) + ofs, to_read, b ); vol->cluster_size_bits ) + ofs, to_read, b );
/* If everything ok, update progress counters and continue. */ /* If everything ok, update progress counters and continue. */
if (bytes_read > 0) { if ( bytes_read > 0 )
{
total += bytes_read; total += bytes_read;
count -= bytes_read; count -= bytes_read;
b = ( u8* )b + bytes_read; b = ( u8* )b + bytes_read;
@ -1187,7 +1246,8 @@ s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
s64 written, to_write, total = 0; s64 written, to_write, total = 0;
int err = EIO; int err = EIO;
if (!vol || !rl || pos < 0 || count < 0) { if ( !vol || !rl || pos < 0 || count < 0 )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "Failed to write runlist [vol: %p rl: %p " ntfs_log_perror( "Failed to write runlist [vol: %p rl: %p "
"pos: %lld count: %lld]", vol, rl, "pos: %lld count: %lld]", vol, rl,
@ -1198,16 +1258,19 @@ s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
goto out; goto out;
/* Seek in @rl to the run containing @pos. */ /* Seek in @rl to the run containing @pos. */
while ( rl->length && ( ofs + ( rl->length << while ( rl->length && ( ofs + ( rl->length <<
vol->cluster_size_bits) <= pos)) { vol->cluster_size_bits ) <= pos ) )
{
ofs += ( rl->length << vol->cluster_size_bits ); ofs += ( rl->length << vol->cluster_size_bits );
rl++; rl++;
} }
/* Offset in the run at which to begin writing. */ /* Offset in the run at which to begin writing. */
ofs = pos - ofs; ofs = pos - ofs;
for (total = 0LL; count; rl++, ofs = 0) { for ( total = 0LL; count; rl++, ofs = 0 )
{
if ( !rl->length ) if ( !rl->length )
goto rl_err_out; goto rl_err_out;
if (rl->lcn < (LCN)0) { if ( rl->lcn < ( LCN )0 )
{
if ( rl->lcn != ( LCN )LCN_HOLE ) if ( rl->lcn != ( LCN )LCN_HOLE )
goto rl_err_out; goto rl_err_out;
@ -1231,7 +1294,8 @@ retry:
else else
written = to_write; written = to_write;
/* If everything ok, update progress counters and continue. */ /* If everything ok, update progress counters and continue. */
if (written > 0) { if ( written > 0 )
{
total += written; total += written;
count -= written; count -= written;
b = ( u8* )b + written; b = ( u8* )b + written;
@ -1275,12 +1339,15 @@ int ntfs_get_nr_significant_bytes(const s64 n)
l = ( n < 0 ? ~n : n ); l = ( n < 0 ? ~n : n );
i = 1; i = 1;
if (l >= 128) { if ( l >= 128 )
{
l >>= 7; l >>= 7;
do { do
{
i++; i++;
l >>= 8; l >>= 8;
} while (l); }
while ( l );
} }
return i; return i;
} }
@ -1311,14 +1378,17 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
LCN prev_lcn; LCN prev_lcn;
int rls; int rls;
if (start_vcn < 0) { if ( start_vcn < 0 )
{
ntfs_log_trace( "start_vcn %lld (should be >= 0)\n", ntfs_log_trace( "start_vcn %lld (should be >= 0)\n",
( long long ) start_vcn ); ( long long ) start_vcn );
errno = EINVAL; errno = EINVAL;
goto errno_set; goto errno_set;
} }
if (!rl) { if ( !rl )
if (start_vcn) { {
if ( start_vcn )
{
ntfs_log_trace( "rl NULL, start_vcn %lld (should be > 0)\n", ntfs_log_trace( "rl NULL, start_vcn %lld (should be > 0)\n",
( long long ) start_vcn ); ( long long ) start_vcn );
errno = EINVAL; errno = EINVAL;
@ -1330,7 +1400,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
/* Skip to runlist element containing @start_vcn. */ /* Skip to runlist element containing @start_vcn. */
while ( rl->length && start_vcn >= rl[1].vcn ) while ( rl->length && start_vcn >= rl[1].vcn )
rl++; rl++;
if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) { if ( ( !rl->length && start_vcn > rl->vcn ) || start_vcn < rl->vcn )
{
errno = EINVAL; errno = EINVAL;
goto errno_set; goto errno_set;
} }
@ -1338,7 +1409,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
/* Always need the terminating zero byte. */ /* Always need the terminating zero byte. */
rls = 1; rls = 1;
/* Do the first partial run if present. */ /* Do the first partial run if present. */
if (start_vcn > rl->vcn) { if ( start_vcn > rl->vcn )
{
s64 delta; s64 delta;
/* We know rl->length != 0 already. */ /* We know rl->length != 0 already. */
@ -1354,7 +1426,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
* Note: this assumes that on NTFS 1.2-, holes are stored with * Note: this assumes that on NTFS 1.2-, holes are stored with
* an lcn of -1 and not a delta_lcn of -1 (unless both are -1). * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
*/ */
if (rl->lcn >= 0 || vol->major_ver < 3) { if ( rl->lcn >= 0 || vol->major_ver < 3 )
{
prev_lcn = rl->lcn; prev_lcn = rl->lcn;
if ( rl->lcn >= 0 ) if ( rl->lcn >= 0 )
prev_lcn += delta; prev_lcn += delta;
@ -1365,7 +1438,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
rl++; rl++;
} }
/* Do the full runs. */ /* Do the full runs. */
for (; rl->length && (rls <= max_size); rl++) { for ( ; rl->length && ( rls <= max_size ); rl++ )
{
if ( rl->length < 0 || rl->lcn < LCN_HOLE ) if ( rl->length < 0 || rl->lcn < LCN_HOLE )
goto err_out; goto err_out;
/* Header byte + length. */ /* Header byte + length. */
@ -1377,7 +1451,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
* Note: this assumes that on NTFS 1.2-, holes are stored with * Note: this assumes that on NTFS 1.2-, holes are stored with
* an lcn of -1 and not a delta_lcn of -1 (unless both are -1). * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
*/ */
if (rl->lcn >= 0 || vol->major_ver < 3) { if ( rl->lcn >= 0 || vol->major_ver < 3 )
{
/* Change in lcn. */ /* Change in lcn. */
rls += ntfs_get_nr_significant_bytes( rl->lcn - rls += ntfs_get_nr_significant_bytes( rl->lcn -
prev_lcn ); prev_lcn );
@ -1421,21 +1496,26 @@ int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n)
s8 j; s8 j;
i = 0; i = 0;
do { do
{
if ( dst > dst_max ) if ( dst > dst_max )
goto err_out; goto err_out;
*dst++ = l & 0xffLL; *dst++ = l & 0xffLL;
l >>= 8; l >>= 8;
i++; i++;
} while (l != 0LL && l != -1LL); }
while ( l != 0LL && l != -1LL );
j = ( n >> 8 * ( i - 1 ) ) & 0xff; j = ( n >> 8 * ( i - 1 ) ) & 0xff;
/* If the sign bit is wrong, we need an extra byte. */ /* If the sign bit is wrong, we need an extra byte. */
if (n < 0LL && j >= 0) { if ( n < 0LL && j >= 0 )
{
if ( dst > dst_max ) if ( dst > dst_max )
goto err_out; goto err_out;
i++; i++;
*dst = ( u8 ) - 1; *dst = ( u8 ) - 1;
} else if (n > 0LL && j < 0) { }
else if ( n > 0LL && j < 0 )
{
if ( dst > dst_max ) if ( dst > dst_max )
goto err_out; goto err_out;
i++; i++;
@ -1489,7 +1569,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
if ( start_vcn < 0 ) if ( start_vcn < 0 )
goto val_err; goto val_err;
if (!rl) { if ( !rl )
{
if ( start_vcn ) if ( start_vcn )
goto val_err; goto val_err;
if ( stop_rl ) if ( stop_rl )
@ -1510,7 +1591,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
dst_max = dst + dst_len - 1; dst_max = dst + dst_len - 1;
prev_lcn = 0; prev_lcn = 0;
/* Do the first partial run if present. */ /* Do the first partial run if present. */
if (start_vcn > rl->vcn) { if ( start_vcn > rl->vcn )
{
s64 delta; s64 delta;
/* We know rl->length != 0 already. */ /* We know rl->length != 0 already. */
@ -1531,7 +1613,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
* case on NT4. - We assume that we just need to write the lcn * case on NT4. - We assume that we just need to write the lcn
* change until someone tells us otherwise... (AIA) * change until someone tells us otherwise... (AIA)
*/ */
if (rl->lcn >= 0 || vol->major_ver < 3) { if ( rl->lcn >= 0 || vol->major_ver < 3 )
{
prev_lcn = rl->lcn; prev_lcn = rl->lcn;
if ( rl->lcn >= 0 ) if ( rl->lcn >= 0 )
prev_lcn += delta; prev_lcn += delta;
@ -1540,7 +1623,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
len_len, dst_max, prev_lcn ); len_len, dst_max, prev_lcn );
if ( lcn_len < 0 ) if ( lcn_len < 0 )
goto size_err; goto size_err;
} else }
else
lcn_len = 0; lcn_len = 0;
dst_next = dst + len_len + lcn_len + 1; dst_next = dst + len_len + lcn_len + 1;
if ( dst_next > dst_max ) if ( dst_next > dst_max )
@ -1553,7 +1637,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
rl++; rl++;
} }
/* Do the full runs. */ /* Do the full runs. */
for (; rl->length; rl++) { for ( ; rl->length; rl++ )
{
if ( rl->length < 0 || rl->lcn < LCN_HOLE ) if ( rl->length < 0 || rl->lcn < LCN_HOLE )
goto err_out; goto err_out;
/* Write length. */ /* Write length. */
@ -1570,14 +1655,16 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
* case on NT4. - We assume that we just need to write the lcn * case on NT4. - We assume that we just need to write the lcn
* change until someone tells us otherwise... (AIA) * change until someone tells us otherwise... (AIA)
*/ */
if (rl->lcn >= 0 || vol->major_ver < 3) { if ( rl->lcn >= 0 || vol->major_ver < 3 )
{
/* Write change in lcn. */ /* Write change in lcn. */
lcn_len = ntfs_write_significant_bytes( dst + 1 + lcn_len = ntfs_write_significant_bytes( dst + 1 +
len_len, dst_max, rl->lcn - prev_lcn ); len_len, dst_max, rl->lcn - prev_lcn );
if ( lcn_len < 0 ) if ( lcn_len < 0 )
goto size_err; goto size_err;
prev_lcn = rl->lcn; prev_lcn = rl->lcn;
} else }
else
lcn_len = 0; lcn_len = 0;
dst_next = dst + len_len + lcn_len + 1; dst_next = dst + len_len + lcn_len + 1;
if ( dst_next > dst_max ) if ( dst_next > dst_max )
@ -1635,7 +1722,8 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
runlist *rl; runlist *rl;
BOOL is_end = FALSE; BOOL is_end = FALSE;
if (!arl || !*arl) { if ( !arl || !*arl )
{
errno = EINVAL; errno = EINVAL;
if ( !arl ) if ( !arl )
ntfs_log_perror( "rl_truncate error: arl: %p", arl ); ntfs_log_perror( "rl_truncate error: arl: %p", arl );
@ -1647,20 +1735,23 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
rl = *arl; rl = *arl;
if (start_vcn < rl->vcn) { if ( start_vcn < rl->vcn )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "Start_vcn lies outside front of runlist" ); ntfs_log_perror( "Start_vcn lies outside front of runlist" );
return -1; return -1;
} }
/* Find the starting vcn in the run list. */ /* Find the starting vcn in the run list. */
while (rl->length) { while ( rl->length )
{
if ( start_vcn < rl[1].vcn ) if ( start_vcn < rl[1].vcn )
break; break;
rl++; rl++;
} }
if (!rl->length) { if ( !rl->length )
{
errno = EIO; errno = EIO;
ntfs_log_trace( "Truncating already truncated runlist?\n" ); ntfs_log_trace( "Truncating already truncated runlist?\n" );
return -1; return -1;
@ -1674,7 +1765,8 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
* element a terminator instead of the truncated runlist * element a terminator instead of the truncated runlist
* element itself. * element itself.
*/ */
if (rl->length) { if ( rl->length )
{
++rl; ++rl;
if ( !rl->length ) if ( !rl->length )
is_end = TRUE; is_end = TRUE;
@ -1708,15 +1800,18 @@ int ntfs_rl_sparse(runlist *rl)
{ {
runlist *rlc; runlist *rlc;
if (!rl) { if ( !rl )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: ", __FUNCTION__ ); ntfs_log_perror( "%s: ", __FUNCTION__ );
return -1; return -1;
} }
for ( rlc = rl; rlc->length; rlc++ ) for ( rlc = rl; rlc->length; rlc++ )
if (rlc->lcn < 0) { if ( rlc->lcn < 0 )
if (rlc->lcn != LCN_HOLE) { {
if ( rlc->lcn != LCN_HOLE )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ ); ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
return -1; return -1;
@ -1738,20 +1833,25 @@ s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl)
runlist *rlc; runlist *rlc;
s64 ret = 0; s64 ret = 0;
if (!rl) { if ( !rl )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: ", __FUNCTION__ ); ntfs_log_perror( "%s: ", __FUNCTION__ );
return -1; return -1;
} }
for (rlc = rl; rlc->length; rlc++) { for ( rlc = rl; rlc->length; rlc++ )
if (rlc->lcn < 0) { {
if (rlc->lcn != LCN_HOLE) { if ( rlc->lcn < 0 )
{
if ( rlc->lcn != LCN_HOLE )
{
errno = EINVAL; errno = EINVAL;
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ ); ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
return -1; return -1;
} }
} else }
else
ret += rlc->length; ret += rlc->length;
} }
return ret << vol->cluster_size_bits; return ret << vol->cluster_size_bits;
@ -1784,7 +1884,8 @@ static void test_rl_dump_runlist(const runlist_element *rl)
int i; int i;
const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "XXXX" }; const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "XXXX" };
if (!rl) { if ( !rl )
{
printf( " Run list not present.\n" ); printf( " Run list not present.\n" );
return; return;
} }
@ -1793,24 +1894,28 @@ static void test_rl_dump_runlist(const runlist_element *rl)
for ( len = 0; rl[len].length; len++ ) ; for ( len = 0; rl[len].length; len++ ) ;
printf( " VCN LCN len\n" ); printf( " VCN LCN len\n" );
for (i = 0; ; i++, rl++) { for ( i = 0; ; i++, rl++ )
{
LCN lcn = rl->lcn; LCN lcn = rl->lcn;
if ((abbr) && (len > 20)) { if ( ( abbr ) && ( len > 20 ) )
{
if ( i == 4 ) if ( i == 4 )
printf( " ...\n" ); printf( " ...\n" );
if ( ( i > 3 ) && ( i < ( len - 3 ) ) ) if ( ( i > 3 ) && ( i < ( len - 3 ) ) )
continue; continue;
} }
if (lcn < (LCN)0) { if ( lcn < ( LCN )0 )
{
int ind = -lcn - 1; int ind = -lcn - 1;
if ( ind > -LCN_ENOENT - 1 ) if ( ind > -LCN_ENOENT - 1 )
ind = 3; ind = 3;
printf( "%8lld %8s %8lld\n", printf( "%8lld %8s %8lld\n",
rl->vcn, lcn_str[ind], rl->length ); rl->vcn, lcn_str[ind], rl->length );
} else }
else
printf( "%8lld %8lld %8lld\n", printf( "%8lld %8lld %8lld\n",
rl->vcn, rl->lcn, rl->length ); rl->vcn, rl->lcn, rl->length );
if ( !rl->length ) if ( !rl->length )
@ -1862,12 +1967,14 @@ static int test_rl_read_buffer(const char *file, u8 *buf, int bufsize)
FILE *fptr; FILE *fptr;
fptr = fopen( file, "r" ); fptr = fopen( file, "r" );
if (!fptr) { if ( !fptr )
{
printf( "open %s\n", file ); printf( "open %s\n", file );
return 0; return 0;
} }
if (fread(buf, bufsize, 1, fptr) == 99) { if ( fread( buf, bufsize, 1, fptr ) == 99 )
{
printf( "read %s\n", file ); printf( "read %s\n", file );
return 0; return 0;
} }
@ -1901,13 +2008,16 @@ static runlist_element * test_rl_pure_src(BOOL contig, BOOL multi, int vcn, int
if ( !result ) if ( !result )
return NULL; return NULL;
if (multi) { if ( multi )
{
MKRL( result + 0, vcn + ( 0*len / 4 ), fudge + vcn + 1000 + ( 0*len / 4 ), len / 4 ) MKRL( result + 0, vcn + ( 0*len / 4 ), fudge + vcn + 1000 + ( 0*len / 4 ), len / 4 )
MKRL( result + 1, vcn + ( 1*len / 4 ), fudge + vcn + 1000 + ( 1*len / 4 ), len / 4 ) MKRL( result + 1, vcn + ( 1*len / 4 ), fudge + vcn + 1000 + ( 1*len / 4 ), len / 4 )
MKRL( result + 2, vcn + ( 2*len / 4 ), fudge + vcn + 1000 + ( 2*len / 4 ), len / 4 ) MKRL( result + 2, vcn + ( 2*len / 4 ), fudge + vcn + 1000 + ( 2*len / 4 ), len / 4 )
MKRL( result + 3, vcn + ( 3*len / 4 ), fudge + vcn + 1000 + ( 3*len / 4 ), len / 4 ) MKRL( result + 3, vcn + ( 3*len / 4 ), fudge + vcn + 1000 + ( 3*len / 4 ), len / 4 )
MKRL( result + 4, vcn + ( 4*len / 4 ), LCN_RL_NOT_MAPPED, 0 ) MKRL( result + 4, vcn + ( 4*len / 4 ), LCN_RL_NOT_MAPPED, 0 )
} else { }
else
{
MKRL( result + 0, vcn, fudge + vcn + 1000, len ) MKRL( result + 0, vcn, fudge + vcn + 1000, len )
MKRL( result + 1, vcn + len, LCN_RL_NOT_MAPPED, 0 ) MKRL( result + 1, vcn + len, LCN_RL_NOT_MAPPED, 0 )
} }
@ -1936,7 +2046,8 @@ static void test_rl_pure_test(int test, BOOL contig, BOOL multi, int vcn, int le
src = test_rl_pure_src( contig, multi, vcn, len ); src = test_rl_pure_src( contig, multi, vcn, len );
dst = ntfs_malloc( 4096 ); dst = ntfs_malloc( 4096 );
if (!src || !dst) { if ( !src || !dst )
{
printf( "Test %2d ---------- FAILED! (no free memory?)\n", test ); printf( "Test %2d ---------- FAILED! (no free memory?)\n", test );
return; return;
} }
@ -1961,7 +2072,8 @@ static void test_rl_pure_test(int test, BOOL contig, BOOL multi, int vcn, int le
static void test_rl_pure( char *contig, char *multi ) static void test_rl_pure( char *contig, char *multi )
{ {
/* VCN, LCN, len */ /* VCN, LCN, len */
static runlist_element file1[] = { static runlist_element file1[] =
{
{ 0, -1, 100 }, /* HOLE */ { 0, -1, 100 }, /* HOLE */
{ 100, 1100, 100 }, /* DATA */ { 100, 1100, 100 }, /* DATA */
{ 200, -1, 100 }, /* HOLE */ { 200, -1, 100 }, /* HOLE */
@ -1969,19 +2081,23 @@ static void test_rl_pure(char *contig, char *multi)
{ 400, -1, 100 }, /* HOLE */ { 400, -1, 100 }, /* HOLE */
{ 500, -3, 0 } /* NOENT */ { 500, -3, 0 } /* NOENT */
}; };
static runlist_element file2[] = { static runlist_element file2[] =
{
{ 0, 1000, 100 }, /* DATA */ { 0, 1000, 100 }, /* DATA */
{ 100, -1, 100 }, /* HOLE */ { 100, -1, 100 }, /* HOLE */
{ 200, -3, 0 } /* NOENT */ { 200, -3, 0 } /* NOENT */
}; };
static runlist_element file3[] = { static runlist_element file3[] =
{
{ 0, 1000, 100 }, /* DATA */ { 0, 1000, 100 }, /* DATA */
{ 100, -3, 0 } /* NOENT */ { 100, -3, 0 } /* NOENT */
}; };
static runlist_element file4[] = { static runlist_element file4[] =
{
{ 0, -3, 0 } /* NOENT */ { 0, -3, 0 } /* NOENT */
}; };
static runlist_element file5[] = { static runlist_element file5[] =
{
{ 0, -2, 100 }, /* NOTMAP */ { 0, -2, 100 }, /* NOTMAP */
{ 100, 1100, 100 }, /* DATA */ { 100, 1100, 100 }, /* DATA */
{ 200, -2, 100 }, /* NOTMAP */ { 200, -2, 100 }, /* NOTMAP */
@ -1989,7 +2105,8 @@ static void test_rl_pure(char *contig, char *multi)
{ 400, -2, 100 }, /* NOTMAP */ { 400, -2, 100 }, /* NOTMAP */
{ 500, -3, 0 } /* NOENT */ { 500, -3, 0 } /* NOENT */
}; };
static runlist_element file6[] = { static runlist_element file6[] =
{
{ 0, 1000, 100 }, /* DATA */ { 0, 1000, 100 }, /* DATA */
{ 100, -2, 100 }, /* NOTMAP */ { 100, -2, 100 }, /* NOTMAP */
{ 200, -3, 0 } /* NOENT */ { 200, -3, 0 } /* NOENT */
@ -2000,7 +2117,8 @@ static void test_rl_pure(char *contig, char *multi)
c = TRUE; c = TRUE;
else if ( strcmp( contig, "noncontig" ) == 0 ) else if ( strcmp( contig, "noncontig" ) == 0 )
c = FALSE; c = FALSE;
else { else
{
printf( "rl pure [contig|noncontig] [single|multi]\n" ); printf( "rl pure [contig|noncontig] [single|multi]\n" );
return; return;
} }
@ -2008,7 +2126,8 @@ static void test_rl_pure(char *contig, char *multi)
m = TRUE; m = TRUE;
else if ( strcmp( multi, "single" ) == 0 ) else if ( strcmp( multi, "single" ) == 0 )
m = FALSE; m = FALSE;
else { else
{
printf( "rl pure [contig|noncontig] [single|multi]\n" ); printf( "rl pure [contig|noncontig] [single|multi]\n" );
return; return;
} }

View File

@ -43,7 +43,8 @@ typedef runlist_element runlist;
* When lcn == -1 this means that the count vcns starting at vcn are not * When lcn == -1 this means that the count vcns starting at vcn are not
* physically allocated (i.e. this is a hole / data is sparse). * physically allocated (i.e. this is a hole / data is sparse).
*/ */
struct _runlist_element {/* In memory vcn to lcn mapping structure element. */ struct _runlist_element /* In memory vcn to lcn mapping structure element. */
{
VCN vcn; /* vcn = Starting virtual cluster number. */ VCN vcn; /* vcn = Starting virtual cluster number. */
LCN lcn; /* lcn = Starting logical cluster number. */ LCN lcn; /* lcn = Starting logical cluster number. */
s64 length; /* Run length in clusters. */ s64 length; /* Run length in clusters. */

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,8 @@ typedef u32 be32;
* item in the mapping list * item in the mapping list
*/ */
struct MAPPING { struct MAPPING
{
struct MAPPING *next; struct MAPPING *next;
int xid; /* linux id : uid or gid */ int xid; /* linux id : uid or gid */
SID *sid; /* Windows id : usid or gsid */ SID *sid; /* Windows id : usid or gsid */
@ -63,7 +64,8 @@ struct MAPPING {
* Note : this cache is not organized as a generic cache * Note : this cache is not organized as a generic cache
*/ */
struct CACHED_PERMISSIONS { struct CACHED_PERMISSIONS
{
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
le32 inh_fileid; le32 inh_fileid;
@ -80,7 +82,8 @@ struct CACHED_PERMISSIONS {
* Entry in the permissions cache for directories with no security_id * Entry in the permissions cache for directories with no security_id
*/ */
struct CACHED_PERMISSIONS_LEGACY { struct CACHED_PERMISSIONS_LEGACY
{
struct CACHED_PERMISSIONS_LEGACY *next; struct CACHED_PERMISSIONS_LEGACY *next;
struct CACHED_PERMISSIONS_LEGACY *previous; struct CACHED_PERMISSIONS_LEGACY *previous;
void *variable; void *variable;
@ -94,7 +97,8 @@ struct CACHED_PERMISSIONS_LEGACY {
* Entry in the securid cache * Entry in the securid cache
*/ */
struct CACHED_SECURID { struct CACHED_SECURID
{
struct CACHED_SECURID *next; struct CACHED_SECURID *next;
struct CACHED_SECURID *previous; struct CACHED_SECURID *previous;
void *variable; void *variable;
@ -111,7 +115,8 @@ struct CACHED_SECURID {
* (has no cache structure by itself) * (has no cache structure by itself)
*/ */
struct CACHED_PERMISSIONS_HEADER { struct CACHED_PERMISSIONS_HEADER
{
unsigned int last; unsigned int last;
/* statistics for permissions */ /* statistics for permissions */
unsigned long p_writes; unsigned long p_writes;
@ -123,7 +128,8 @@ struct CACHED_PERMISSIONS_HEADER {
* The whole permissions cache * The whole permissions cache
*/ */
struct PERMISSIONS_CACHE { struct PERMISSIONS_CACHE
{
struct CACHED_PERMISSIONS_HEADER head; struct CACHED_PERMISSIONS_HEADER head;
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */ struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
} ; } ;
@ -132,7 +138,8 @@ struct PERMISSIONS_CACHE {
* Security flags values * Security flags values
*/ */
enum { enum
{
SECURITY_DEFAULT, /* rely on fuse for permissions checking */ SECURITY_DEFAULT, /* rely on fuse for permissions checking */
SECURITY_RAW, /* force same ownership/permissions on files */ SECURITY_RAW, /* force same ownership/permissions on files */
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */ SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
@ -146,7 +153,8 @@ enum {
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ; enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
struct SECURITY_CONTEXT { struct SECURITY_CONTEXT
{
ntfs_volume *vol; ntfs_volume *vol;
struct MAPPING *mapping[MAPCOUNT]; struct MAPPING *mapping[MAPCOUNT];
struct PERMISSIONS_CACHE **pseccache; struct PERMISSIONS_CACHE **pseccache;
@ -162,20 +170,23 @@ struct SECURITY_CONTEXT {
* Posix ACL structures * Posix ACL structures
*/ */
struct POSIX_ACE { struct POSIX_ACE
{
u16 tag; u16 tag;
u16 perms; u16 perms;
s32 id; s32 id;
} ; } ;
struct POSIX_ACL { struct POSIX_ACL
{
u8 version; u8 version;
u8 flags; u8 flags;
u16 filler; u16 filler;
struct POSIX_ACE ace[0]; struct POSIX_ACE ace[0];
} ; } ;
struct POSIX_SECURITY { struct POSIX_SECURITY
{
mode_t mode; mode_t mode;
int acccnt; int acccnt;
int defcnt; int defcnt;
@ -188,7 +199,8 @@ struct POSIX_SECURITY {
* Posix tags, cpu-endian 16 bits * Posix tags, cpu-endian 16 bits
*/ */
enum { enum
{
POSIX_ACL_USER_OBJ = 1, POSIX_ACL_USER_OBJ = 1,
POSIX_ACL_USER = 2, POSIX_ACL_USER = 2,
POSIX_ACL_GROUP_OBJ = 4, POSIX_ACL_GROUP_OBJ = 4,
@ -204,7 +216,8 @@ enum {
* Posix permissions, cpu-endian 16 bits * Posix permissions, cpu-endian 16 bits
*/ */
enum { enum
{
POSIX_PERM_X = 1, POSIX_PERM_X = 1,
POSIX_PERM_W = 2, POSIX_PERM_W = 2,
POSIX_PERM_R = 4, POSIX_PERM_R = 4,
@ -310,7 +323,8 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni,
#define MAGIC_API 0x09042009 #define MAGIC_API 0x09042009
struct SECURITY_API { struct SECURITY_API
{
u32 magic; u32 magic;
struct SECURITY_CONTEXT security; struct SECURITY_CONTEXT security;
struct PERMISSIONS_CACHE *seccache; struct PERMISSIONS_CACHE *seccache;

View File

@ -92,7 +92,8 @@ typedef sle64 leLSN;
/** /**
* enum BOOL - These are just to make the code more readable... * enum BOOL - These are just to make the code more readable...
*/ */
typedef enum { typedef enum
{
#ifndef FALSE #ifndef FALSE
FALSE = 0, FALSE = 0,
#endif #endif
@ -118,7 +119,8 @@ typedef enum {
/** /**
* enum IGNORE_CASE_BOOL - * enum IGNORE_CASE_BOOL -
*/ */
typedef enum { typedef enum
{
CASE_SENSITIVE = 0, CASE_SENSITIVE = 0,
IGNORE_CASE = 1, IGNORE_CASE = 1,
} IGNORE_CASE_BOOL; } IGNORE_CASE_BOOL;

View File

@ -88,7 +88,8 @@ static int nfconvert_utf8 = 1;
* characters are (in)valid. * characters are (in)valid.
*/ */
#if 0 #if 0
static const u8 legal_ansi_char_array[0x40] = { static const u8 legal_ansi_char_array[0x40] =
{
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
@ -158,20 +159,25 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
u16 u1, u2; u16 u1, u2;
#ifdef DEBUG #ifdef DEBUG
if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) { if ( !name1 || !name2 || ( ic && ( !upcase || !upcase_len ) ) )
{
ntfs_log_debug( "ntfs_names_collate received NULL pointer!\n" ); ntfs_log_debug( "ntfs_names_collate received NULL pointer!\n" );
exit( 1 ); exit( 1 );
} }
#endif #endif
cnt = min( name1_len, name2_len ); cnt = min( name1_len, name2_len );
if (cnt > 0) { if ( cnt > 0 )
if (ic == CASE_SENSITIVE) { {
do { if ( ic == CASE_SENSITIVE )
{
do
{
c1 = le16_to_cpu( *name1 ); c1 = le16_to_cpu( *name1 );
name1++; name1++;
c2 = le16_to_cpu( *name2 ); c2 = le16_to_cpu( *name2 );
name2++; name2++;
} while (--cnt && (c1 == c2)); }
while ( --cnt && ( c1 == c2 ) );
u1 = c1; u1 = c1;
u2 = c2; u2 = c2;
if ( u1 < upcase_len ) if ( u1 < upcase_len )
@ -179,7 +185,8 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
if ( u2 < upcase_len ) if ( u2 < upcase_len )
u2 = le16_to_cpu( upcase[u2] ); u2 = le16_to_cpu( upcase[u2] );
if ( ( u1 == u2 ) && cnt ) if ( ( u1 == u2 ) && cnt )
do { do
{
u1 = le16_to_cpu( *name1 ); u1 = le16_to_cpu( *name1 );
name1++; name1++;
u2 = le16_to_cpu( *name2 ); u2 = le16_to_cpu( *name2 );
@ -188,7 +195,8 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
u1 = le16_to_cpu( upcase[u1] ); u1 = le16_to_cpu( upcase[u1] );
if ( u2 < upcase_len ) if ( u2 < upcase_len )
u2 = le16_to_cpu( upcase[u2] ); u2 = le16_to_cpu( upcase[u2] );
} while ((u1 == u2) && --cnt); }
while ( ( u1 == u2 ) && --cnt );
if ( u1 < u2 ) if ( u1 < u2 )
return -1; return -1;
if ( u1 > u2 ) if ( u1 > u2 )
@ -201,8 +209,11 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
return -1; return -1;
if ( c1 > c2 ) if ( c1 > c2 )
return 1; return 1;
} else { }
do { else
{
do
{
u1 = c1 = le16_to_cpu( *name1 ); u1 = c1 = le16_to_cpu( *name1 );
name1++; name1++;
u2 = c2 = le16_to_cpu( *name2 ); u2 = c2 = le16_to_cpu( *name2 );
@ -211,7 +222,8 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
u1 = le16_to_cpu( upcase[u1] ); u1 = le16_to_cpu( upcase[u1] );
if ( u2 < upcase_len ) if ( u2 < upcase_len )
u2 = le16_to_cpu( upcase[u2] ); u2 = le16_to_cpu( upcase[u2] );
} while ((u1 == u2) && --cnt); }
while ( ( u1 == u2 ) && --cnt );
if ( u1 < u2 ) if ( u1 < u2 )
return -1; return -1;
if ( u1 > u2 ) if ( u1 > u2 )
@ -221,7 +233,9 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
if ( name1_len > name2_len ) if ( name1_len > name2_len )
return 1; return 1;
} }
} else { }
else
{
if ( name1_len < name2_len ) if ( name1_len < name2_len )
return -1; return -1;
if ( name1_len > name2_len ) if ( name1_len > name2_len )
@ -250,12 +264,14 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
size_t i; size_t i;
#ifdef DEBUG #ifdef DEBUG
if (!s1 || !s2) { if ( !s1 || !s2 )
{
ntfs_log_debug( "ntfs_wcsncmp() received NULL pointer!\n" ); ntfs_log_debug( "ntfs_wcsncmp() received NULL pointer!\n" );
exit( 1 ); exit( 1 );
} }
#endif #endif
for (i = 0; i < n; ++i) { for ( i = 0; i < n; ++i )
{
c1 = le16_to_cpu( s1[i] ); c1 = le16_to_cpu( s1[i] );
c2 = le16_to_cpu( s2[i] ); c2 = le16_to_cpu( s2[i] );
if ( c1 < c2 ) if ( c1 < c2 )
@ -293,12 +309,14 @@ int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
size_t i; size_t i;
#ifdef DEBUG #ifdef DEBUG
if (!s1 || !s2 || !upcase) { if ( !s1 || !s2 || !upcase )
{
ntfs_log_debug( "ntfs_wcsncasecmp() received NULL pointer!\n" ); ntfs_log_debug( "ntfs_wcsncasecmp() received NULL pointer!\n" );
exit( 1 ); exit( 1 );
} }
#endif #endif
for (i = 0; i < n; ++i) { for ( i = 0; i < n; ++i )
{
if ( ( c1 = le16_to_cpu( s1[i] ) ) < upcase_size ) if ( ( c1 = le16_to_cpu( s1[i] ) ) < upcase_size )
c1 = le16_to_cpu( upcase[c1] ); c1 = le16_to_cpu( upcase[c1] );
if ( ( c2 = le16_to_cpu( s2[i] ) ) < upcase_size ) if ( ( c2 = le16_to_cpu( s2[i] ) ) < upcase_size )
@ -329,7 +347,8 @@ u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen)
{ {
u32 i; u32 i;
for (i = 0; i < maxlen; i++) { for ( i = 0; i < maxlen; i++ )
{
if ( !le16_to_cpu( s[i] ) ) if ( !le16_to_cpu( s[i] ) )
break; break;
} }
@ -360,7 +379,8 @@ ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
len = ntfs_ucsnlen( s, maxlen ); len = ntfs_ucsnlen( s, maxlen );
dst = ntfs_malloc( ( len + 1 ) * sizeof( ntfschar ) ); dst = ntfs_malloc( ( len + 1 ) * sizeof( ntfschar ) );
if (dst) { if ( dst )
{
memcpy( dst, s, len * sizeof( ntfschar ) ); memcpy( dst, s, len * sizeof( ntfschar ) );
dst[len] = cpu_to_le16( L'\0' ); dst[len] = cpu_to_le16( L'\0' );
} }
@ -458,16 +478,20 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
BOOL surrog; BOOL surrog;
surrog = FALSE; surrog = FALSE;
for (i = 0; i < ins_len && ins[i]; i++) { for ( i = 0; i < ins_len && ins[i]; i++ )
{
unsigned short c = le16_to_cpu( ins[i] ); unsigned short c = le16_to_cpu( ins[i] );
if (surrog) { if ( surrog )
if ((c >= 0xdc00) && (c < 0xe000)) { {
if ( ( c >= 0xdc00 ) && ( c < 0xe000 ) )
{
surrog = FALSE; surrog = FALSE;
count += 4; count += 4;
} else }
else
goto fail; goto fail;
} else }
if (c < 0x80) else if ( c < 0x80 )
count++; count++;
else if ( c < 0x800 ) else if ( c < 0x800 )
count += 2; count += 2;
@ -483,7 +507,8 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
count += 3; count += 3;
else else
goto fail; goto fail;
if (count > outs_len) { if ( count > outs_len )
{
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto out; goto out;
} }
@ -531,7 +556,8 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
if ( size < 0 ) if ( size < 0 )
goto out; goto out;
if (!*outs) { if ( !*outs )
{
outs_len = size + 1; outs_len = size + 1;
*outs = ntfs_malloc( outs_len ); *outs = ntfs_malloc( outs_len );
if ( !*outs ) if ( !*outs )
@ -540,35 +566,49 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
t = *outs; t = *outs;
for (i = 0; i < ins_len && ins[i]; i++) { for ( i = 0; i < ins_len && ins[i]; i++ )
{
unsigned short c = le16_to_cpu( ins[i] ); unsigned short c = le16_to_cpu( ins[i] );
/* size not double-checked */ /* size not double-checked */
if (halfpair) { if ( halfpair )
if ((c >= 0xdc00) && (c < 0xe000)) { {
if ( ( c >= 0xdc00 ) && ( c < 0xe000 ) )
{
*t++ = 0xf0 + ( ( ( halfpair + 64 ) >> 8 ) & 7 ); *t++ = 0xf0 + ( ( ( halfpair + 64 ) >> 8 ) & 7 );
*t++ = 0x80 + ( ( ( halfpair + 64 ) >> 2 ) & 63 ); *t++ = 0x80 + ( ( ( halfpair + 64 ) >> 2 ) & 63 );
*t++ = 0x80 + ( ( c >> 6 ) & 15 ) + ( ( halfpair & 3 ) << 4 ); *t++ = 0x80 + ( ( c >> 6 ) & 15 ) + ( ( halfpair & 3 ) << 4 );
*t++ = 0x80 + ( c & 63 ); *t++ = 0x80 + ( c & 63 );
halfpair = 0; halfpair = 0;
} else }
else
goto fail; goto fail;
} else if (c < 0x80) { }
else if ( c < 0x80 )
{
*t++ = c; *t++ = c;
} else { }
if (c < 0x800) { else
{
if ( c < 0x800 )
{
*t++ = ( 0xc0 | ( ( c >> 6 ) & 0x3f ) ); *t++ = ( 0xc0 | ( ( c >> 6 ) & 0x3f ) );
*t++ = 0x80 | ( c & 0x3f ); *t++ = 0x80 | ( c & 0x3f );
} else if (c < 0xd800) { }
else if ( c < 0xd800 )
{
*t++ = 0xe0 | ( c >> 12 ); *t++ = 0xe0 | ( c >> 12 );
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f ); *t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
*t++ = 0x80 | ( c & 0x3f ); *t++ = 0x80 | ( c & 0x3f );
} else if (c < 0xdc00) }
else if ( c < 0xdc00 )
halfpair = c; halfpair = c;
else if (c >= 0xe000) { else if ( c >= 0xe000 )
{
*t++ = 0xe0 | ( c >> 12 ); *t++ = 0xe0 | ( c >> 12 );
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f ); *t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
*t++ = 0x80 | ( c & 0x3f ); *t++ = 0x80 | ( c & 0x3f );
} else }
else
goto fail; goto fail;
} }
} }
@ -576,17 +616,21 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
#if defined(__APPLE__) || defined(__DARWIN__) #if defined(__APPLE__) || defined(__DARWIN__)
#ifdef ENABLE_NFCONV #ifdef ENABLE_NFCONV
if(nfconvert_utf8 && (t - *outs) > 0) { if ( nfconvert_utf8 && ( t - *outs ) > 0 )
{
char *new_outs = NULL; char *new_outs = NULL;
int new_outs_len = ntfs_macosx_normalize_utf8( *outs, &new_outs, 0 ); // Normalize to decomposed form int new_outs_len = ntfs_macosx_normalize_utf8( *outs, &new_outs, 0 ); // Normalize to decomposed form
if(new_outs_len >= 0 && new_outs != NULL) { if ( new_outs_len >= 0 && new_outs != NULL )
if(original_outs_value != *outs) { {
if ( original_outs_value != *outs )
{
// We have allocated outs ourselves. // We have allocated outs ourselves.
free( *outs ); free( *outs );
*outs = new_outs; *outs = new_outs;
t = *outs + new_outs_len; t = *outs + new_outs_len;
} }
else { else
{
// We need to copy new_outs into the fixed outs buffer. // We need to copy new_outs into the fixed outs buffer.
memset( *outs, 0, original_outs_len ); memset( *outs, 0, original_outs_len );
strncpy( *outs, new_outs, original_outs_len - 1 ); strncpy( *outs, new_outs, original_outs_len - 1 );
@ -594,7 +638,8 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
free( new_outs ); free( new_outs );
} }
} }
else { else
{
ntfs_log_error( "Failed to normalize NTFS string to UTF-8 NFD: %s\n", *outs ); ntfs_log_error( "Failed to normalize NTFS string to UTF-8 NFD: %s\n", *outs );
ntfs_log_error( " new_outs=0x%p\n", new_outs ); ntfs_log_error( " new_outs=0x%p\n", new_outs );
ntfs_log_error( " new_outs_len=%d\n", new_outs_len ); ntfs_log_error( " new_outs_len=%d\n", new_outs_len );
@ -626,11 +671,14 @@ static int utf8_to_utf16_size(const char *s)
unsigned int byte; unsigned int byte;
size_t count = 0; size_t count = 0;
while ((byte = *((const unsigned char *)s++))) { while ( ( byte = *( ( const unsigned char * )s++ ) ) )
{
if ( ++count >= PATH_MAX ) if ( ++count >= PATH_MAX )
goto fail; goto fail;
if (byte >= 0xc0) { if ( byte >= 0xc0 )
if (byte >= 0xF5) { {
if ( byte >= 0xF5 )
{
errno = EILSEQ; errno = EILSEQ;
goto out; goto out;
} }
@ -644,7 +692,8 @@ static int utf8_to_utf16_size(const char *s)
s++; s++;
if ( !*s ) if ( !*s )
break; break;
if (byte >= 0xF0) { if ( byte >= 0xF0 )
{
s++; s++;
if ( ++count >= PATH_MAX ) if ( ++count >= PATH_MAX )
goto fail; goto fail;
@ -670,25 +719,37 @@ static int utf8_to_unicode(u32 *wc, const char *s)
unsigned int byte = *( ( const unsigned char * )s ); unsigned int byte = *( ( const unsigned char * )s );
/* single byte */ /* single byte */
if (byte == 0) { if ( byte == 0 )
{
*wc = ( u32 ) 0; *wc = ( u32 ) 0;
return 0; return 0;
} else if (byte < 0x80) { }
else if ( byte < 0x80 )
{
*wc = ( u32 ) byte; *wc = ( u32 ) byte;
return 1; return 1;
/* double byte */ /* double byte */
} else if (byte < 0xc2) { }
else if ( byte < 0xc2 )
{
goto fail; goto fail;
} else if (byte < 0xE0) { }
if ((s[1] & 0xC0) == 0x80) { else if ( byte < 0xE0 )
{
if ( ( s[1] & 0xC0 ) == 0x80 )
{
*wc = ( ( u32 )( byte & 0x1F ) << 6 ) *wc = ( ( u32 )( byte & 0x1F ) << 6 )
| ( ( u32 )( s[1] & 0x3F ) ); | ( ( u32 )( s[1] & 0x3F ) );
return 2; return 2;
} else }
else
goto fail; goto fail;
/* three-byte */ /* three-byte */
} else if (byte < 0xF0) { }
if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)) { else if ( byte < 0xF0 )
{
if ( ( ( s[1] & 0xC0 ) == 0x80 ) && ( ( s[2] & 0xC0 ) == 0x80 ) )
{
*wc = ( ( u32 )( byte & 0x0F ) << 12 ) *wc = ( ( u32 )( byte & 0x0F ) << 12 )
| ( ( u32 )( s[1] & 0x3F ) << 6 ) | ( ( u32 )( s[1] & 0x3F ) << 6 )
| ( ( u32 )( s[2] & 0x3F ) ); | ( ( u32 )( s[2] & 0x3F ) );
@ -705,9 +766,12 @@ static int utf8_to_unicode(u32 *wc, const char *s)
} }
goto fail; goto fail;
/* four-byte */ /* four-byte */
} else if (byte < 0xF5) { }
else if ( byte < 0xF5 )
{
if ( ( ( s[1] & 0xC0 ) == 0x80 ) && ( ( s[2] & 0xC0 ) == 0x80 ) if ( ( ( s[1] & 0xC0 ) == 0x80 ) && ( ( s[2] & 0xC0 ) == 0x80 )
&& ((s[3] & 0xC0) == 0x80)) { && ( ( s[3] & 0xC0 ) == 0x80 ) )
{
*wc = ( ( u32 )( byte & 0x07 ) << 18 ) *wc = ( ( u32 )( byte & 0x07 ) << 18 )
| ( ( u32 )( s[1] & 0x3F ) << 12 ) | ( ( u32 )( s[1] & 0x3F ) << 12 )
| ( ( u32 )( s[2] & 0x3F ) << 6 ) | ( ( u32 )( s[2] & 0x3F ) << 6 )
@ -736,7 +800,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
#if defined(__APPLE__) || defined(__DARWIN__) #if defined(__APPLE__) || defined(__DARWIN__)
#ifdef ENABLE_NFCONV #ifdef ENABLE_NFCONV
char *new_ins = NULL; char *new_ins = NULL;
if(nfconvert_utf8) { if ( nfconvert_utf8 )
{
int new_ins_len; int new_ins_len;
new_ins_len = ntfs_macosx_normalize_utf8( ins, &new_ins, 1 ); // Normalize to composed form new_ins_len = ntfs_macosx_normalize_utf8( ins, &new_ins, 1 ); // Normalize to composed form
if ( new_ins_len >= 0 ) if ( new_ins_len >= 0 )
@ -757,7 +822,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
goto fail; goto fail;
allocated = FALSE; allocated = FALSE;
if (!*outs) { if ( !*outs )
{
*outs = ntfs_malloc( ( shorts + 1 ) * sizeof( ntfschar ) ); *outs = ntfs_malloc( ( shorts + 1 ) * sizeof( ntfschar ) );
if ( !*outs ) if ( !*outs )
goto fail; goto fail;
@ -766,12 +832,16 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
outpos = *outs; outpos = *outs;
while(1) { while ( 1 )
{
int m = utf8_to_unicode( &wc, t ); int m = utf8_to_unicode( &wc, t );
if (m <= 0) { if ( m <= 0 )
if (m < 0) { {
if ( m < 0 )
{
/* do not leave space allocated if failed */ /* do not leave space allocated if failed */
if (allocated) { if ( allocated )
{
free( *outs ); free( *outs );
*outs = ( ntfschar* )NULL; *outs = ( ntfschar* )NULL;
} }
@ -782,7 +852,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
} }
if ( wc < 0x10000 ) if ( wc < 0x10000 )
*outpos++ = cpu_to_le16( wc ); *outpos++ = cpu_to_le16( wc );
else { else
{
wc -= 0x10000; wc -= 0x10000;
*outpos++ = cpu_to_le16( ( wc >> 10 ) + 0xd800 ); *outpos++ = cpu_to_le16( ( wc >> 10 ) + 0xd800 );
*outpos++ = cpu_to_le16( ( wc & 0x3ff ) + 0xdc00 ); *outpos++ = cpu_to_le16( ( wc & 0x3ff ) + 0xdc00 );
@ -837,19 +908,22 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
mbstate_t mbstate; mbstate_t mbstate;
#endif #endif
if (!ins || !outs) { if ( !ins || !outs )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
mbs = *outs; mbs = *outs;
mbs_len = outs_len; mbs_len = outs_len;
if (mbs && !mbs_len) { if ( mbs && !mbs_len )
{
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return -1; return -1;
} }
if ( use_utf8 ) if ( use_utf8 )
return ntfs_utf16_to_utf8( ins, ins_len, outs, outs_len ); return ntfs_utf16_to_utf8( ins, ins_len, outs, outs_len );
if (!mbs) { if ( !mbs )
{
mbs_len = ( ins_len + 1 ) * MB_CUR_MAX; mbs_len = ( ins_len + 1 ) * MB_CUR_MAX;
mbs = ntfs_malloc( mbs_len ); mbs = ntfs_malloc( mbs_len );
if ( !mbs ) if ( !mbs )
@ -860,11 +934,14 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
#else #else
wctomb( NULL, 0 ); wctomb( NULL, 0 );
#endif #endif
for (i = o = 0; i < ins_len; i++) { for ( i = o = 0; i < ins_len; i++ )
{
/* Reallocate memory if necessary or abort. */ /* Reallocate memory if necessary or abort. */
if ((int)(o + MB_CUR_MAX) > mbs_len) { if ( ( int )( o + MB_CUR_MAX ) > mbs_len )
{
char *tc; char *tc;
if (mbs == *outs) { if ( mbs == *outs )
{
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return -1; return -1;
} }
@ -888,7 +965,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
#endif #endif
if ( cnt == -1 ) if ( cnt == -1 )
goto err_out; goto err_out;
if (cnt <= 0) { if ( cnt <= 0 )
{
ntfs_log_debug( "Eeek. cnt <= 0, cnt = %i\n", cnt ); ntfs_log_debug( "Eeek. cnt <= 0, cnt = %i\n", cnt );
errno = EINVAL; errno = EINVAL;
goto err_out; goto err_out;
@ -897,7 +975,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
} }
#ifdef HAVE_MBSINIT #ifdef HAVE_MBSINIT
/* Make sure we are back in the initial state. */ /* Make sure we are back in the initial state. */
if (!mbsinit(&mbstate)) { if ( !mbsinit( &mbstate ) )
{
ntfs_log_debug( "Eeek. mbstate not in initial state!\n" ); ntfs_log_debug( "Eeek. mbstate not in initial state!\n" );
errno = EILSEQ; errno = EILSEQ;
goto err_out; goto err_out;
@ -909,7 +988,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
*outs = mbs; *outs = mbs;
return o; return o;
err_out: err_out:
if (mbs != *outs) { if ( mbs != *outs )
{
int eo = errno; int eo = errno;
free( mbs ); free( mbs );
errno = eo; errno = eo;
@ -950,7 +1030,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
mbstate_t mbstate; mbstate_t mbstate;
#endif #endif
if (!ins || !outs) { if ( !ins || !outs )
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -966,7 +1047,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
memset( &mbstate, 0, sizeof( mbstate ) ); memset( &mbstate, 0, sizeof( mbstate ) );
ins_len = mbsrtowcs( NULL, ( const char ** ) & s, 0, &mbstate ); ins_len = mbsrtowcs( NULL, ( const char ** ) & s, 0, &mbstate );
#ifdef __CYGWIN32__ #ifdef __CYGWIN32__
if (!ins_len && *ins) { if ( !ins_len && *ins )
{
/* Older Cygwin had broken mbsrtowcs() implementation. */ /* Older Cygwin had broken mbsrtowcs() implementation. */
ins_len = strlen( ins ); ins_len = strlen( ins );
} }
@ -980,9 +1062,11 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
if ( ins_len == -1 ) if ( ins_len == -1 )
return ins_len; return ins_len;
#ifdef HAVE_MBSINIT #ifdef HAVE_MBSINIT
if ((s != ins) || !mbsinit(&mbstate)) { if ( ( s != ins ) || !mbsinit( &mbstate ) )
{
#else #else
if (s != ins) { if ( s != ins )
{
#endif #endif
errno = EILSEQ; errno = EILSEQ;
return -1; return -1;
@ -998,9 +1082,11 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
#else #else
mbtowc( NULL, NULL, 0 ); mbtowc( NULL, NULL, 0 );
#endif #endif
for (i = o = cnt = 0; i < ins_size; i += cnt, o++) { for ( i = o = cnt = 0; i < ins_size; i += cnt, o++ )
{
/* Reallocate memory if necessary. */ /* Reallocate memory if necessary. */
if (o >= ucs_len) { if ( o >= ucs_len )
{
ntfschar *tc; ntfschar *tc;
ucs_len = ( ucs_len * sizeof( ntfschar ) + 64 ) & ~63; ucs_len = ( ucs_len * sizeof( ntfschar ) + 64 ) & ~63;
tc = realloc( ucs, ucs_len ); tc = realloc( ucs, ucs_len );
@ -1019,14 +1105,16 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
break; break;
if ( cnt == -1 ) if ( cnt == -1 )
goto err_out; goto err_out;
if (cnt < -1) { if ( cnt < -1 )
{
ntfs_log_trace( "Eeek. cnt = %i\n", cnt ); ntfs_log_trace( "Eeek. cnt = %i\n", cnt );
errno = EINVAL; errno = EINVAL;
goto err_out; goto err_out;
} }
/* Make sure we are not overflowing the NTFS Unicode set. */ /* Make sure we are not overflowing the NTFS Unicode set. */
if ( ( unsigned long )wc >= ( unsigned long )( 1 << if ( ( unsigned long )wc >= ( unsigned long )( 1 <<
(8 * sizeof(ntfschar)))) { ( 8 * sizeof( ntfschar ) ) ) )
{
errno = EILSEQ; errno = EILSEQ;
goto err_out; goto err_out;
} }
@ -1035,7 +1123,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
} }
#ifdef HAVE_MBSINIT #ifdef HAVE_MBSINIT
/* Make sure we are back in the initial state. */ /* Make sure we are back in the initial state. */
if (!mbsinit(&mbstate)) { if ( !mbsinit( &mbstate ) )
{
ntfs_log_trace( "Eeek. mbstate not in initial state!\n" ); ntfs_log_trace( "Eeek. mbstate not in initial state!\n" );
errno = EILSEQ; errno = EILSEQ;
goto err_out; goto err_out;
@ -1069,24 +1158,32 @@ char *ntfs_uppercase_mbs(const char *low,
size = strlen( low ); size = strlen( low );
upp = ( char* )ntfs_malloc( 3 * size + 1 ); upp = ( char* )ntfs_malloc( 3 * size + 1 );
if (upp) { if ( upp )
{
s = low; s = low;
t = upp; t = upp;
do { do
{
n = utf8_to_unicode( &wc, s ); n = utf8_to_unicode( &wc, s );
if (n > 0) { if ( n > 0 )
{
if ( wc < upcase_size ) if ( wc < upcase_size )
wc = le16_to_cpu( upcase[wc] ); wc = le16_to_cpu( upcase[wc] );
if ( wc < 0x80 ) if ( wc < 0x80 )
*t++ = wc; *t++ = wc;
else if (wc < 0x800) { else if ( wc < 0x800 )
{
*t++ = ( 0xc0 | ( ( wc >> 6 ) & 0x3f ) ); *t++ = ( 0xc0 | ( ( wc >> 6 ) & 0x3f ) );
*t++ = 0x80 | ( wc & 0x3f ); *t++ = 0x80 | ( wc & 0x3f );
} else if (wc < 0x10000) { }
else if ( wc < 0x10000 )
{
*t++ = 0xe0 | ( wc >> 12 ); *t++ = 0xe0 | ( wc >> 12 );
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f ); *t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
*t++ = 0x80 | ( wc & 0x3f ); *t++ = 0x80 | ( wc & 0x3f );
} else { }
else
{
*t++ = 0xf0 | ( ( wc >> 18 ) & 7 ); *t++ = 0xf0 | ( ( wc >> 18 ) & 7 );
*t++ = 0x80 | ( ( wc >> 12 ) & 63 ); *t++ = 0x80 | ( ( wc >> 12 ) & 63 );
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f ); *t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
@ -1094,8 +1191,10 @@ char *ntfs_uppercase_mbs(const char *low,
} }
s += n; s += n;
} }
} while (n > 0); }
if (n < 0) { while ( n > 0 );
if ( n < 0 )
{
free( upp ); free( upp );
upp = ( char* )NULL; upp = ( char* )NULL;
errno = EILSEQ; errno = EILSEQ;
@ -1117,7 +1216,8 @@ char *ntfs_uppercase_mbs(const char *low,
*/ */
void ntfs_upcase_table_build( ntfschar *uc, u32 uc_len ) void ntfs_upcase_table_build( ntfschar *uc, u32 uc_len )
{ {
static int uc_run_table[][3] = { /* Start, End, Add */ static int uc_run_table[][3] = /* Start, End, Add */
{
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
@ -1133,7 +1233,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32}, {0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
{0} {0}
}; };
static int uc_dup_table[][2] = { /* Start, End */ static int uc_dup_table[][2] = /* Start, End */
{
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
@ -1142,7 +1243,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
{0} {0}
}; };
static int uc_byte_table[][2] = { /* Offset, Value */ static int uc_byte_table[][2] = /* Offset, Value */
{
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
@ -1162,7 +1264,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
uc_len = 65536; uc_len = 65536;
for ( i = 0; ( u32 )i < uc_len; i++ ) for ( i = 0; ( u32 )i < uc_len; i++ )
uc[i] = cpu_to_le16( i ); uc[i] = cpu_to_le16( i );
for (r = 0; uc_run_table[r][0]; r++) { for ( r = 0; uc_run_table[r][0]; r++ )
{
off = uc_run_table[r][2]; off = uc_run_table[r][2];
for ( i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++ ) for ( i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++ )
uc[i] = cpu_to_le16( i + off ); uc[i] = cpu_to_le16( i + off );
@ -1170,7 +1273,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
for ( r = 0; uc_dup_table[r][0]; r++ ) for ( r = 0; uc_dup_table[r][0]; r++ )
for ( i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2 ) for ( i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2 )
uc[i + 1] = cpu_to_le16( i ); uc[i + 1] = cpu_to_le16( i );
for (r = 0; uc_byte_table[r][0]; r++) { for ( r = 0; uc_byte_table[r][0]; r++ )
{
k = uc_byte_table[r][1]; k = uc_byte_table[r][1];
uc[uc_byte_table[r][0]] = cpu_to_le16( k ); uc[uc_byte_table[r][0]] = cpu_to_le16( k );
} }
@ -1195,15 +1299,18 @@ ntfschar *ntfs_locase_table_build(const ntfschar *uc, u32 uc_cnt)
u32 i; u32 i;
lc = ( ntfschar* )ntfs_malloc( uc_cnt * sizeof( ntfschar ) ); lc = ( ntfschar* )ntfs_malloc( uc_cnt * sizeof( ntfschar ) );
if (lc) { if ( lc )
{
for ( i = 0; i < uc_cnt; i++ ) for ( i = 0; i < uc_cnt; i++ )
lc[i] = cpu_to_le16( i ); lc[i] = cpu_to_le16( i );
for (i=0; i<uc_cnt; i++) { for ( i = 0; i < uc_cnt; i++ )
{
upp = le16_to_cpu( uc[i] ); upp = le16_to_cpu( uc[i] );
if ( ( upp != i ) && ( upp < uc_cnt ) ) if ( ( upp != i ) && ( upp < uc_cnt ) )
lc[upp] = cpu_to_le16( i ); lc[upp] = cpu_to_le16( i );
} }
} else }
else
ntfs_log_error( "Could not build the locase table\n" ); ntfs_log_error( "Could not build the locase table\n" );
return ( lc ); return ( lc );
} }
@ -1229,16 +1336,19 @@ ntfschar *ntfs_str2ucs(const char *s, int *len)
{ {
ntfschar *ucs = NULL; ntfschar *ucs = NULL;
if (s && ((*len = ntfs_mbstoucs(s, &ucs)) == -1)) { if ( s && ( ( *len = ntfs_mbstoucs( s, &ucs ) ) == -1 ) )
{
ntfs_log_perror( "Couldn't convert '%s' to Unicode", s ); ntfs_log_perror( "Couldn't convert '%s' to Unicode", s );
return NULL; return NULL;
} }
if (*len > NTFS_MAX_NAME_LEN) { if ( *len > NTFS_MAX_NAME_LEN )
{
free( ucs ); free( ucs );
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return NULL; return NULL;
} }
if (!ucs || !*len) { if ( !ucs || !*len )
{
ucs = AT_UNNAMED; ucs = AT_UNNAMED;
*len = 0; *len = 0;
} }
@ -1282,7 +1392,8 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
forbidden = ( len == 0 ) forbidden = ( len == 0 )
|| ( le16_to_cpu( name[len-1] ) == ' ' ) || ( le16_to_cpu( name[len-1] ) == ' ' )
|| ( le16_to_cpu( name[len-1] ) == '.' ); || ( le16_to_cpu( name[len-1] ) == '.' );
for (i=0; i<len; i++) { for ( i = 0; i < len; i++ )
{
ch = le16_to_cpu( name[i] ); ch = le16_to_cpu( name[i] );
if ( ( ch < 0x20 ) if ( ( ch < 0x20 )
|| ( ( ch < 0x40 ) || ( ( ch < 0x40 )
@ -1314,7 +1425,8 @@ BOOL ntfs_collapsible_chars(ntfs_volume *vol,
collapsible = shortlen == longlen; collapsible = shortlen == longlen;
if ( collapsible ) if ( collapsible )
for (i=0; i<shortlen; i++) { for ( i = 0; i < shortlen; i++ )
{
ch = le16_to_cpu( longname[i] ); ch = le16_to_cpu( longname[i] );
if ( ( ch >= vol->upcase_len ) if ( ( ch >= vol->upcase_len )
|| ( ( shortname[i] != longname[i] ) || ( ( shortname[i] != longname[i] )
@ -1335,10 +1447,10 @@ int ntfs_set_char_encoding(const char *locale)
if ( !locale || strstr( locale, "utf8" ) || strstr( locale, "UTF8" ) if ( !locale || strstr( locale, "utf8" ) || strstr( locale, "UTF8" )
|| strstr( locale, "utf-8" ) || strstr( locale, "UTF-8" ) ) || strstr( locale, "utf-8" ) || strstr( locale, "UTF-8" ) )
use_utf8 = 1; use_utf8 = 1;
else else if ( setlocale( LC_ALL, locale ) )
if (setlocale(LC_ALL, locale))
use_utf8 = 0; use_utf8 = 0;
else { else
{
ntfs_log_error( "Invalid locale, encoding to UTF-8\n" ); ntfs_log_error( "Invalid locale, encoding to UTF-8\n" );
use_utf8 = 1; use_utf8 = 1;
} }
@ -1347,9 +1459,11 @@ int ntfs_set_char_encoding(const char *locale)
#if defined(__APPLE__) || defined(__DARWIN__) #if defined(__APPLE__) || defined(__DARWIN__)
int ntfs_macosx_normalize_filenames(int normalize) { int ntfs_macosx_normalize_filenames( int normalize )
{
#ifdef ENABLE_NFCONV #ifdef ENABLE_NFCONV
if(normalize == 0 || normalize == 1) { if ( normalize == 0 || normalize == 1 )
{
nfconvert_utf8 = normalize; nfconvert_utf8 = normalize;
return 0; return 0;
} }
@ -1361,7 +1475,8 @@ int ntfs_macosx_normalize_filenames(int normalize) {
} }
int ntfs_macosx_normalize_utf8( const char *utf8_string, char **target, int ntfs_macosx_normalize_utf8( const char *utf8_string, char **target,
int composed) { int composed )
{
#ifdef ENABLE_NFCONV #ifdef ENABLE_NFCONV
/* For this code to compile, the CoreFoundation framework must be fed to the linker. */ /* For this code to compile, the CoreFoundation framework must be fed to the linker. */
CFStringRef cfSourceString; CFStringRef cfSourceString;
@ -1373,7 +1488,8 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
/* Convert the UTF-8 string to a CFString. */ /* Convert the UTF-8 string to a CFString. */
cfSourceString = CFStringCreateWithCString( kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8 ); cfSourceString = CFStringCreateWithCString( kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8 );
if(cfSourceString == NULL) { if ( cfSourceString == NULL )
{
ntfs_log_error( "CFStringCreateWithCString failed!\n" ); ntfs_log_error( "CFStringCreateWithCString failed!\n" );
return -2; return -2;
} }
@ -1381,7 +1497,8 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
/* Create a mutable string from cfSourceString that we are free to modify. */ /* Create a mutable string from cfSourceString that we are free to modify. */
cfMutableString = CFStringCreateMutableCopy( kCFAllocatorDefault, 0, cfSourceString ); cfMutableString = CFStringCreateMutableCopy( kCFAllocatorDefault, 0, cfSourceString );
CFRelease( cfSourceString ); /* End-of-life. */ CFRelease( cfSourceString ); /* End-of-life. */
if(cfMutableString == NULL) { if ( cfMutableString == NULL )
{
ntfs_log_error( "CFStringCreateMutableCopy failed!\n" ); ntfs_log_error( "CFStringCreateMutableCopy failed!\n" );
return -3; return -3;
} }
@ -1391,13 +1508,16 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
/* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */ /* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */
rangeToProcess = CFRangeMake( 0, CFStringGetLength( cfMutableString ) ); rangeToProcess = CFRangeMake( 0, CFStringGetLength( cfMutableString ) );
if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength) > 0) { if ( CFStringGetBytes( cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength ) > 0 )
{
resultLength = sizeof( char ) * ( requiredBufferLength + 1 ); resultLength = sizeof( char ) * ( requiredBufferLength + 1 );
result = ntfs_calloc( resultLength ); result = ntfs_calloc( resultLength );
if(result != NULL) { if ( result != NULL )
{
if ( CFStringGetBytes( cfMutableString, rangeToProcess, kCFStringEncodingUTF8, if ( CFStringGetBytes( cfMutableString, rangeToProcess, kCFStringEncodingUTF8,
0, false, (UInt8*)result, resultLength-1, &requiredBufferLength) <= 0) { 0, false, ( UInt8* )result, resultLength - 1, &requiredBufferLength ) <= 0 )
{
ntfs_log_error( "Could not perform UTF-8 conversion of normalized CFMutableString.\n" ); ntfs_log_error( "Could not perform UTF-8 conversion of normalized CFMutableString.\n" );
free( result ); free( result );
result = NULL; result = NULL;
@ -1412,7 +1532,8 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
CFRelease( cfMutableString ); CFRelease( cfMutableString );
if(result != NULL) { if ( result != NULL )
{
*target = result; *target = result;
return resultLength - 1; return resultLength - 1;
} }

Some files were not shown because too many files have changed in this diff Show More