mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-12-18 16:01:58 +01:00
* remove little unused code
* code cleanup
This commit is contained in:
parent
e1a36e8988
commit
9e79c9d99b
@ -2,8 +2,8 @@
|
||||
<app version="1">
|
||||
<name> USB Loader GX</name>
|
||||
<coder>USB Loader GX Team</coder>
|
||||
<version>1.0 r950</version>
|
||||
<release_date>201009182245</release_date>
|
||||
<version>1.0 r951</version>
|
||||
<release_date>201009182308</release_date>
|
||||
<short_description>Loads games from USB-devices</short_description>
|
||||
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
||||
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||
|
BIN
data/magic_patcher.o
Normal file
BIN
data/magic_patcher.o
Normal file
Binary file not shown.
@ -37,7 +37,8 @@
|
||||
*
|
||||
* Font face character glyph relevant data structure.
|
||||
*/
|
||||
typedef struct ftgxCharData_ {
|
||||
typedef struct ftgxCharData_
|
||||
{
|
||||
int16_t renderOffsetX; /**< Texture X axis bearing offset. */
|
||||
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
|
||||
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
|
||||
@ -56,7 +57,8 @@ typedef struct ftgxCharData_ {
|
||||
*
|
||||
* Offset structure which hold both a maximum and minimum value.
|
||||
*/
|
||||
typedef struct ftgxDataOffset_ {
|
||||
typedef struct ftgxDataOffset_
|
||||
{
|
||||
int16_t ascender; /**< Maximum data offset. */
|
||||
int16_t descender; /**< Minimum data offset. */
|
||||
int16_t max; /**< Maximum data offset. */
|
||||
|
@ -121,7 +121,8 @@ bool ZipFile::ExtractAll(const char *dest)
|
||||
|
||||
done += ret;
|
||||
|
||||
} while(done < uncompressed_size);
|
||||
}
|
||||
while ( done < uncompressed_size );
|
||||
|
||||
fclose( pfile );
|
||||
unzCloseCurrentFile( File );
|
||||
|
@ -15,7 +15,8 @@
|
||||
*
|
||||
* Initializes the Wii's audio subsystem
|
||||
***************************************************************************/
|
||||
void InitAudio() {
|
||||
void InitAudio()
|
||||
{
|
||||
AUDIO_Init( NULL );
|
||||
ASND_Init();
|
||||
ASND_Pause( 0 );
|
||||
@ -27,7 +28,8 @@ void InitAudio() {
|
||||
* Shuts down audio subsystem. Useful to avoid unpleasant sounds if a
|
||||
* crash occurs during shutdown.
|
||||
***************************************************************************/
|
||||
void ShutdownAudio() {
|
||||
void ShutdownAudio()
|
||||
{
|
||||
ASND_Pause( 1 );
|
||||
ASND_End();
|
||||
}
|
||||
|
@ -552,7 +552,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
|
||||
file = fopen( src, "rb" );
|
||||
|
||||
if (file==NULL){
|
||||
if ( file == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -569,7 +570,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
|
||||
unsigned char * buffer = malloc( blksize );
|
||||
|
||||
if(buffer == NULL){
|
||||
if ( buffer == NULL )
|
||||
{
|
||||
//no memory
|
||||
fclose( file );
|
||||
return NULL;
|
||||
@ -580,7 +582,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
read = fread( buffer, 1, blksize, file );
|
||||
( void )auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
|
||||
|
||||
} while(read > 0);
|
||||
}
|
||||
while ( read > 0 );
|
||||
|
||||
fclose( file );
|
||||
free( buffer );
|
||||
|
@ -39,7 +39,8 @@ s32 dump_banner(const u8* discid,const char * dest)
|
||||
|
||||
ret = WDVD_OpenPartition( offset );
|
||||
|
||||
if (ret < 0) {
|
||||
if ( ret < 0 )
|
||||
{
|
||||
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
||||
|
||||
FILE *tplfp = fopen( tplfilepath, "rb" );
|
||||
|
||||
if(tplfp !=NULL) {
|
||||
if ( tplfp != NULL )
|
||||
{
|
||||
|
||||
unsigned short heighttemp = 0;
|
||||
unsigned short widthtemp = 0;
|
||||
@ -27,7 +28,8 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
||||
tplfilesize = ftell ( tplfp );
|
||||
rewind ( tplfp );
|
||||
memory = memalign( 32, tplfilesize );
|
||||
if(!memory) {
|
||||
if ( !memory )
|
||||
{
|
||||
fclose( tplfp );
|
||||
return;
|
||||
}
|
||||
@ -38,13 +40,15 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
||||
int ret;
|
||||
|
||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
||||
if(ret < 0) {
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
||||
if(ret < 0) {
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
@ -56,7 +60,9 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
||||
widescreen = 0;
|
||||
filecheck = true;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
filecheck = false;
|
||||
fclose( tplfp );
|
||||
}
|
||||
@ -76,13 +82,15 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
||||
int ret;
|
||||
|
||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
||||
if(ret < 0) {
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
||||
if(ret < 0) {
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
@ -94,7 +102,8 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
||||
|
||||
GuiBanner::~GuiBanner()
|
||||
{
|
||||
if(memory != NULL) {
|
||||
if ( memory != NULL )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
}
|
||||
|
@ -72,7 +72,8 @@ void md5(u8 *data, u32 len, u8 *hash)
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 zeroes[0x40];
|
||||
u32 imet; // "IMET"
|
||||
u8 zero_six_zero_three[8]; // fixed, unknown purpose
|
||||
@ -89,7 +90,8 @@ typedef struct {
|
||||
u8 crypto[0x10];
|
||||
} imet_data_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 imd5_tag; // 0x494D4435 "IMD5";
|
||||
u32 size; // size of the rest of part B, starting from next field.
|
||||
u8 zeroes[8];
|
||||
@ -148,13 +150,16 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
||||
|
||||
out_ptr = decompressed_data;
|
||||
|
||||
while (in_ptr < data_end) {
|
||||
while ( in_ptr < data_end )
|
||||
{
|
||||
int bit;
|
||||
u8 bitmask = *in_ptr;
|
||||
|
||||
in_ptr++;
|
||||
for (bit = 0x80; bit != 0; bit >>= 1) {
|
||||
if (bitmask & bit) {
|
||||
for ( bit = 0x80; bit != 0; bit >>= 1 )
|
||||
{
|
||||
if ( bitmask & bit )
|
||||
{
|
||||
// Next section is compressed
|
||||
u8 rep_length;
|
||||
u16 rep_offset;
|
||||
@ -164,14 +169,17 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
||||
in_ptr++;
|
||||
rep_offset = *in_ptr | ( rep_offset << 8 );
|
||||
in_ptr++;
|
||||
if (out_ptr-decompressed_data < rep_offset) {
|
||||
if ( out_ptr - decompressed_data < rep_offset )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ; rep_length > 0; rep_length--) {
|
||||
for ( ; rep_length > 0; rep_length-- )
|
||||
{
|
||||
*out_ptr = out_ptr[-rep_offset-1];
|
||||
out_ptr++;
|
||||
if (out_ptr >= out_end) {
|
||||
if ( out_ptr >= out_end )
|
||||
{
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just copy byte
|
||||
*out_ptr = *in_ptr;
|
||||
out_ptr++;
|
||||
if (out_ptr >= out_end) {
|
||||
if ( out_ptr >= out_end )
|
||||
{
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||
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;
|
||||
|
||||
tag = be32( ( u8* ) & header->imd5_tag );
|
||||
if (tag != 0x494D4435) {
|
||||
if ( tag != 0x494D4435 )
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
md5( data + 32, size - 32, md5_calc );
|
||||
if (memcmp(&header->md5, md5_calc, 0x10)) {
|
||||
if ( memcmp( &header->md5, md5_calc, 0x10 ) )
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
size_in_imd5 = be32( ( u8* ) & header->size );
|
||||
if (size_in_imd5 != size - 32) {
|
||||
if ( size_in_imd5 != size - 32 )
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
tag = be32( ( u8* ) & header->payload_tag );
|
||||
if (tag == 0x4C5A3737) {
|
||||
if ( tag == 0x4C5A3737 )
|
||||
{
|
||||
// "LZ77" - uncompress
|
||||
decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size );
|
||||
if ( decompressed_data == NULL )
|
||||
@ -233,7 +248,9 @@ static int write_imd5_lz77(u8* data, size_t size, char* outname)
|
||||
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
|
||||
|
||||
free( decompressed_data );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
write_file( &header->payload_tag, size - 32, outname );
|
||||
//printf(", md5 ok");
|
||||
}
|
||||
@ -257,7 +274,8 @@ static int do_U8_archive(FILE *fp)
|
||||
|
||||
fread( &header, 1, sizeof header, fp );
|
||||
tag = be32( ( u8* ) & header.tag );
|
||||
if (tag != 0x55AA382D) {
|
||||
if ( tag != 0x55AA382D )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -275,7 +293,8 @@ static int do_U8_archive(FILE *fp)
|
||||
fread( string_table, 1, rest_size, fp );
|
||||
current_offset = data_offset;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
for ( i = 0; i < num_nodes; i++ )
|
||||
{
|
||||
U8_node* node = &nodes[i];
|
||||
u16 type = be16( ( u8* ) & node->type );
|
||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
||||
@ -284,25 +303,31 @@ static int do_U8_archive(FILE *fp)
|
||||
char* name = ( char* ) & string_table[name_offset];
|
||||
u8* file_data;
|
||||
|
||||
if (type == 0x0100) {
|
||||
if ( type == 0x0100 )
|
||||
{
|
||||
// Directory
|
||||
mkdir( name, 0777 );
|
||||
chdir( name );
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal file
|
||||
u8 padding[32];
|
||||
|
||||
if (type != 0x0000) {
|
||||
if ( type != 0x0000 )
|
||||
{
|
||||
free( string_table );
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (current_offset < my_data_offset) {
|
||||
if ( current_offset < my_data_offset )
|
||||
{
|
||||
int diff = my_data_offset - current_offset;
|
||||
|
||||
if (diff > 32) {
|
||||
if ( diff > 32 )
|
||||
{
|
||||
free( string_table );
|
||||
return -3;
|
||||
}
|
||||
@ -316,14 +341,16 @@ static int do_U8_archive(FILE *fp)
|
||||
int result;
|
||||
result = write_imd5_lz77( file_data, size, name );
|
||||
if ( result < 0 )
|
||||
{free(string_table);
|
||||
{
|
||||
free( string_table );
|
||||
return result;
|
||||
}
|
||||
//printf(")\n");
|
||||
current_offset += size;
|
||||
}
|
||||
|
||||
while (dir_stack[dir_index] == i+2 && dir_index > 0) {
|
||||
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
||||
{
|
||||
chdir( ".." );
|
||||
dir_index--;
|
||||
}
|
||||
@ -357,7 +384,8 @@ void do_U8_archivebanner(FILE *fp)
|
||||
|
||||
fread( &header, 1, sizeof header, fp );
|
||||
tag = be32( ( u8* ) & header.tag );
|
||||
if (tag != 0x55AA382D) {
|
||||
if ( tag != 0x55AA382D )
|
||||
{
|
||||
//printf("No U8 tag");
|
||||
exit( 0 );
|
||||
}
|
||||
@ -375,7 +403,8 @@ void do_U8_archivebanner(FILE *fp)
|
||||
string_table = malloc( rest_size );
|
||||
fread( string_table, 1, rest_size, fp );
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
for ( i = 0; i < num_nodes; i++ )
|
||||
{
|
||||
U8_node* node = &nodes[i];
|
||||
u16 type = be16( ( u8* ) & node->type );
|
||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
||||
@ -384,16 +413,20 @@ void do_U8_archivebanner(FILE *fp)
|
||||
char* name = ( char* ) & string_table[name_offset];
|
||||
u8* file_data;
|
||||
|
||||
if (type == 0x0100) {
|
||||
if ( type == 0x0100 )
|
||||
{
|
||||
// Directory
|
||||
mkdir( name, 0777 );
|
||||
chdir( name );
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal file
|
||||
|
||||
if (type != 0x0000) {
|
||||
if ( type != 0x0000 )
|
||||
{
|
||||
printf( "Unknown type" );
|
||||
exit( 0 );
|
||||
}
|
||||
@ -406,7 +439,8 @@ void do_U8_archivebanner(FILE *fp)
|
||||
//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( ".." );
|
||||
dir_index--;
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ extern GuiWindow * mainWindow;
|
||||
/****************************************************************************
|
||||
* CheatMenu
|
||||
***************************************************************************/
|
||||
int CheatMenu(const char * gameID) {
|
||||
int CheatMenu( const char * gameID )
|
||||
{
|
||||
int choice = 0;
|
||||
bool exit = false;
|
||||
int ret = 1;
|
||||
@ -65,7 +66,8 @@ int CheatMenu(const char * gameID) {
|
||||
|
||||
int download = 0;
|
||||
|
||||
switch (check) {
|
||||
switch ( check )
|
||||
{
|
||||
case -1:
|
||||
WindowPrompt( tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ) );
|
||||
break;
|
||||
@ -92,7 +94,8 @@ int CheatMenu(const char * gameID) {
|
||||
titleTxt.SetMaxWidth( 350, SCROLL_HORIZONTAL );
|
||||
titleTxt.SetPosition( 12, 40 );
|
||||
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
for ( int i = 0; i <= cntcheats; i++ )
|
||||
{
|
||||
cheatslst.SetValue( i, "%s", c.getCheatName( i ).c_str() );
|
||||
cheatslst.SetName( i, "OFF" );
|
||||
}
|
||||
@ -109,34 +112,46 @@ int CheatMenu(const char * gameID) {
|
||||
mainWindow->Append( &w );
|
||||
ResumeGui();
|
||||
|
||||
while (!exit) {
|
||||
while ( !exit )
|
||||
{
|
||||
VIDEO_WaitVSync ();
|
||||
|
||||
ret = chtBrowser.GetClickedOption();
|
||||
if (ret != -1) {
|
||||
if ( ret != -1 )
|
||||
{
|
||||
const char *strCheck = cheatslst.GetName( ret );
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
||||
{
|
||||
cheatslst.SetName( ret, "%s", "OFF" );
|
||||
} else if (strncmp(strCheck,"OFF",3) == 0) {
|
||||
}
|
||||
else if ( strncmp( strCheck, "OFF", 3 ) == 0 )
|
||||
{
|
||||
cheatslst.SetName( ret, "%s", "ON" );
|
||||
}
|
||||
}
|
||||
|
||||
if (createBtn.GetState() == STATE_CLICKED) {
|
||||
if ( createBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
createBtn.ResetState();
|
||||
if (cntcheats > 0) {
|
||||
if ( cntcheats > 0 )
|
||||
{
|
||||
int selectednrs[30];
|
||||
int x = 0;
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
for ( int i = 0; i <= cntcheats; i++ )
|
||||
{
|
||||
const char *strCheck = cheatslst.GetName( i );
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
||||
{
|
||||
selectednrs[x] = i;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
if (x == 0) {
|
||||
if ( x == 0 )
|
||||
{
|
||||
WindowPrompt( tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ) );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
subfoldercreate( Settings.Cheatcodespath );
|
||||
string chtpath = Settings.Cheatcodespath;
|
||||
string gctfname = chtpath + c.getGameID() + ".gct";
|
||||
@ -145,10 +160,12 @@ int CheatMenu(const char * gameID) {
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
} else WindowPrompt(tr("Error"),tr("Could not create GCT file"),tr("OK"));
|
||||
}
|
||||
else WindowPrompt( tr( "Error" ), tr( "Could not create GCT file" ), tr( "OK" ) );
|
||||
}
|
||||
|
||||
if (backBtn.GetState() == STATE_CLICKED) {
|
||||
if ( backBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
backBtn.ResetState();
|
||||
exit = true;
|
||||
break;
|
||||
|
@ -12,11 +12,13 @@
|
||||
|
||||
#define ERRORRANGE "Error: CheatNr out of range"
|
||||
|
||||
GCTCheats::GCTCheats(void) {
|
||||
GCTCheats::GCTCheats( void )
|
||||
{
|
||||
iCntCheats = 0;
|
||||
}
|
||||
|
||||
GCTCheats::~GCTCheats(void) {
|
||||
GCTCheats::~GCTCheats( void )
|
||||
{
|
||||
|
||||
string sGameID = "";
|
||||
string sGameTitle = "";
|
||||
@ -25,43 +27,59 @@ GCTCheats::~GCTCheats(void) {
|
||||
string sCheatComment[MAXCHEATS];*/
|
||||
}
|
||||
|
||||
int GCTCheats::getCnt() {
|
||||
int GCTCheats::getCnt()
|
||||
{
|
||||
return iCntCheats;
|
||||
}
|
||||
|
||||
string GCTCheats::getGameName(void) {
|
||||
string GCTCheats::getGameName( void )
|
||||
{
|
||||
return sGameTitle;
|
||||
}
|
||||
|
||||
string GCTCheats::getGameID(void) {
|
||||
string GCTCheats::getGameID( void )
|
||||
{
|
||||
return sGameID;
|
||||
}
|
||||
|
||||
string GCTCheats::getCheat(int nr) {
|
||||
if (nr <= (iCntCheats-1)) {
|
||||
string GCTCheats::getCheat( int nr )
|
||||
{
|
||||
if ( nr <= ( iCntCheats - 1 ) )
|
||||
{
|
||||
return sCheats[nr];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERRORRANGE;
|
||||
}
|
||||
}
|
||||
|
||||
string GCTCheats::getCheatName(int nr) {
|
||||
if (nr <= (iCntCheats-1)) {
|
||||
string GCTCheats::getCheatName( int nr )
|
||||
{
|
||||
if ( nr <= ( iCntCheats - 1 ) )
|
||||
{
|
||||
return sCheatName[nr];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERRORRANGE;
|
||||
}
|
||||
}
|
||||
|
||||
string GCTCheats::getCheatComment(int nr) {
|
||||
if (nr <= (iCntCheats-1)) {
|
||||
string GCTCheats::getCheatComment( int nr )
|
||||
{
|
||||
if ( nr <= ( iCntCheats - 1 ) )
|
||||
{
|
||||
return sCheatComment[nr];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERRORRANGE;
|
||||
}
|
||||
}
|
||||
|
||||
int GCTCheats::createGCT(int nr,const char * filename) {
|
||||
int GCTCheats::createGCT( int nr, const char * filename )
|
||||
{
|
||||
|
||||
if ( nr == 0 )
|
||||
return 0;
|
||||
@ -83,7 +101,8 @@ int GCTCheats::createGCT(int nr,const char * filename) {
|
||||
long int li;
|
||||
int len = buf.size();
|
||||
|
||||
while (x < len) {
|
||||
while ( x < len )
|
||||
{
|
||||
string temp = buf.substr( x, 2 );
|
||||
li = strtol( temp.c_str(), NULL, 16 );
|
||||
temp = li;
|
||||
@ -96,7 +115,8 @@ int GCTCheats::createGCT(int nr,const char * filename) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
||||
int GCTCheats::createGCT( const char * chtbuffer, const char * filename )
|
||||
{
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open( filename );
|
||||
@ -115,7 +135,8 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
||||
long int li;
|
||||
int len = buf.size();
|
||||
|
||||
while (x < len) {
|
||||
while ( x < len )
|
||||
{
|
||||
string temp = buf.substr( x, 2 );
|
||||
li = strtol( temp.c_str(), NULL, 16 );
|
||||
temp = li;
|
||||
@ -130,7 +151,8 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
||||
int GCTCheats::createGCT( int nr[], int cnt, const char * filename )
|
||||
{
|
||||
|
||||
if ( cnt == 0 )
|
||||
return 0;
|
||||
@ -148,14 +170,16 @@ int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
||||
filestr.write( header, sizeof( header ) );
|
||||
|
||||
int c = 0;
|
||||
while (c != cnt) {
|
||||
while ( c != cnt )
|
||||
{
|
||||
int actnr = nr[c];
|
||||
string buf = getCheat( actnr );
|
||||
long int li;
|
||||
int len = buf.size();
|
||||
int x = 0;
|
||||
|
||||
while (x < len) {
|
||||
while ( x < len )
|
||||
{
|
||||
string temp = buf.substr( x, 2 );
|
||||
li = strtol( temp.c_str(), NULL, 16 );
|
||||
temp = li;
|
||||
@ -170,7 +194,8 @@ int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GCTCheats::openTxtfile(const char * filename) {
|
||||
int GCTCheats::openTxtfile( const char * filename )
|
||||
{
|
||||
ifstream filestr;
|
||||
int i = 0;
|
||||
string str;
|
||||
@ -196,7 +221,8 @@ int GCTCheats::openTxtfile(const char * filename) {
|
||||
if ( !sGameTitle[sGameTitle.length() - 1] == '\r' )
|
||||
filestr.seekg( 0, ios_base::beg );
|
||||
|
||||
while (!filestr.eof()) {
|
||||
while ( !filestr.eof() )
|
||||
{
|
||||
getline( filestr, sCheatName[i] ); // '\n' delimiter by default
|
||||
if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' )
|
||||
sCheatName[i].erase( sCheatName[i].length() - 1 );
|
||||
@ -204,31 +230,38 @@ int GCTCheats::openTxtfile(const char * filename) {
|
||||
string cheatdata;
|
||||
bool emptyline = false;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
getline( filestr, str );
|
||||
if ( str[str.length() - 1] == '\r' )
|
||||
str.erase( str.length() - 1 );
|
||||
|
||||
if (str == "" || str[0] == '\r' || str[0] == '\n') {
|
||||
if ( str == "" || str[0] == '\r' || str[0] == '\n' )
|
||||
{
|
||||
emptyline = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsCode(str)) {
|
||||
if ( IsCode( str ) )
|
||||
{
|
||||
// remove any garbage (comment) after code
|
||||
while (str.size() > 17) {
|
||||
while ( str.size() > 17 )
|
||||
{
|
||||
str.erase( str.length() - 1 );
|
||||
}
|
||||
cheatdata.append( str );
|
||||
size_t found = cheatdata.find( ' ' );
|
||||
cheatdata.replace( found, 1, "" );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("%i",str.size());
|
||||
sCheatComment[i] = str;
|
||||
}
|
||||
if ( filestr.eof() ) break;
|
||||
|
||||
} while (!emptyline);
|
||||
}
|
||||
while ( !emptyline );
|
||||
|
||||
sCheats[i] = cheatdata;
|
||||
i++;
|
||||
@ -239,14 +272,17 @@ int GCTCheats::openTxtfile(const char * filename) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GCTCheats::IsCode(const std::string& str) {
|
||||
if (str[8] == ' ' && str.size() >= 17) {
|
||||
bool GCTCheats::IsCode( const std::string& str )
|
||||
{
|
||||
if ( str[8] == ' ' && str.size() >= 17 )
|
||||
{
|
||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||
char part1[9];
|
||||
char part2[9];
|
||||
snprintf( part1, sizeof( part1 ), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7] );
|
||||
snprintf( part2, sizeof( part2 ), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14], str[15], str[16] );
|
||||
if ((strtok(part1,"0123456789ABCDEFabcdef") == NULL) && (strtok(part2,"0123456789ABCDEFabcdef") == NULL)) {
|
||||
if ( ( strtok( part1, "0123456789ABCDEFabcdef" ) == NULL ) && ( strtok( part2, "0123456789ABCDEFabcdef" ) == NULL ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,8 @@
|
||||
using namespace std;
|
||||
|
||||
//!Handles Ocarina TXT Cheatfiles
|
||||
class GCTCheats {
|
||||
class GCTCheats
|
||||
{
|
||||
private:
|
||||
string sGameID;
|
||||
string sGameTitle;
|
||||
|
@ -44,7 +44,8 @@ sec_t fat_wbfs_sec = 0;
|
||||
int fs_ntfs_mount = 0;
|
||||
sec_t fs_ntfs_sec = 0;
|
||||
|
||||
int USBDevice_Init() {
|
||||
int USBDevice_Init()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf( "\nUSBDevice_Init()" );
|
||||
#endif
|
||||
@ -55,7 +56,8 @@ int USBDevice_Init() {
|
||||
//try first mount with cIOS
|
||||
// if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
// //try now mount with libogc
|
||||
if (!fatMount("USB", &__io_usbstorage2, 0, CACHE, SECTORS)) {
|
||||
if ( !fatMount( "USB", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf( ":-1" );
|
||||
#endif
|
||||
@ -71,7 +73,8 @@ int USBDevice_Init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBDevice_deInit() {
|
||||
void USBDevice_deInit()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf( "\nUSBDevice_deInit()" );
|
||||
#endif
|
||||
@ -82,7 +85,8 @@ void USBDevice_deInit() {
|
||||
fat_usb_sec = 0;
|
||||
}
|
||||
|
||||
int WBFSDevice_Init(u32 sector) {
|
||||
int WBFSDevice_Init( u32 sector )
|
||||
{
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount( "WBFS:/" );
|
||||
//right now mounts first FAT-partition
|
||||
@ -90,21 +94,24 @@ int WBFSDevice_Init(u32 sector) {
|
||||
//try first mount with cIOS
|
||||
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
//try now mount with libogc
|
||||
if (!fatMount("WBFS", &__io_usbstorage2, 0, CACHE, SECTORS)) {
|
||||
if ( !fatMount( "WBFS", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
|
||||
fat_wbfs_mount = 1;
|
||||
fat_wbfs_sec = _FAT_startSector;
|
||||
if (sector && fat_wbfs_sec != sector) {
|
||||
if ( sector && fat_wbfs_sec != sector )
|
||||
{
|
||||
// This is an error situation...actually, but is ignored in Config loader also
|
||||
// Should ask Oggzee about it...
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WBFSDevice_deInit() {
|
||||
void WBFSDevice_deInit()
|
||||
{
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount( "WBFS:/" );
|
||||
|
||||
@ -112,21 +119,24 @@ void WBFSDevice_deInit() {
|
||||
fat_wbfs_sec = 0;
|
||||
}
|
||||
|
||||
int isInserted(const char *path) {
|
||||
int isInserted( const char *path )
|
||||
{
|
||||
if ( !strncmp( path, "USB:", 4 ) )
|
||||
return 1;
|
||||
|
||||
return __io_sdhc.isInserted() || __io_wiisd.isInserted();
|
||||
}
|
||||
|
||||
int SDCard_Init() {
|
||||
int SDCard_Init()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf( "\nSDCard_Init()" );
|
||||
#endif
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount( "SD:/" );
|
||||
//right now mounts first FAT-partition
|
||||
if (fatMount("SD", &__io_wiisd, 0, CACHE, SECTORS)) {
|
||||
if ( fatMount( "SD", &__io_wiisd, 0, CACHE, SECTORS ) )
|
||||
{
|
||||
fat_sd_mount = MOUNT_SD;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
#ifdef DEBUG_FAT
|
||||
@ -134,7 +144,8 @@ int SDCard_Init() {
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
else if (fatMount("SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE)) {
|
||||
else if ( fatMount( "SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE ) )
|
||||
{
|
||||
fat_sd_mount = MOUNT_SDHC;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
#ifdef DEBUG_FAT
|
||||
@ -148,7 +159,8 @@ int SDCard_Init() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SDCard_deInit() {
|
||||
void SDCard_deInit()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf( "\nSDCard_deInit()" );
|
||||
#endif
|
||||
@ -178,28 +190,37 @@ s32 MountNTFS(u32 sector)
|
||||
setlocale( LC_CTYPE, "C-UTF-8" );
|
||||
setlocale( LC_MESSAGES, "C-UTF-8" );
|
||||
|
||||
if (wbfsDev == WBFS_DEVICE_USB) {
|
||||
if ( wbfsDev == WBFS_DEVICE_USB )
|
||||
{
|
||||
/* Initialize WBFS interface */
|
||||
// if (!__io_wiiums.startup()) {
|
||||
ret = __io_usbstorage2.startup();
|
||||
if (!ret) {
|
||||
if ( !ret )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
/* Mount device */
|
||||
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||
ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
if (!ret) {
|
||||
if ( !ret )
|
||||
{
|
||||
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 );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
}
|
||||
if (!ret) {
|
||||
if ( !ret )
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define _FATMOUNTER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern int fat_sd_mount;
|
||||
|
@ -4,7 +4,8 @@
|
||||
#define _GECKO_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
char ascii( char s );
|
||||
|
@ -48,7 +48,8 @@ u8 boothomebrew = 0;
|
||||
/****************************************************************************
|
||||
* roundup Function
|
||||
***************************************************************************/
|
||||
int roundup(float number) {
|
||||
int roundup( float number )
|
||||
{
|
||||
if ( number == ( int ) number )
|
||||
return ( int ) number;
|
||||
else
|
||||
@ -58,7 +59,8 @@ int roundup(float number) {
|
||||
/****************************************************************************
|
||||
* MenuHomebrewBrowse
|
||||
***************************************************************************/
|
||||
int MenuHomebrewBrowse() {
|
||||
int MenuHomebrewBrowse()
|
||||
{
|
||||
int menu = MENU_NONE;
|
||||
int choice = 0;
|
||||
|
||||
@ -66,12 +68,14 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
u32 filecount = HomebrewFiles.GetFilecount();
|
||||
|
||||
if (!filecount) {
|
||||
if ( !filecount )
|
||||
{
|
||||
WindowPrompt( tr( "No .dol or .elf files found." ), 0, tr( "OK" ) );
|
||||
return MENU_DISCLIST;
|
||||
}
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
FADE,
|
||||
LEFT,
|
||||
RIGHT
|
||||
@ -141,7 +145,8 @@ int MenuHomebrewBrowse() {
|
||||
GuiImageData *IconData[4];
|
||||
GuiImage *IconImg[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
IconData[i] = NULL;
|
||||
IconImg[i] = NULL;
|
||||
}
|
||||
@ -150,7 +155,8 @@ int MenuHomebrewBrowse() {
|
||||
GuiText backBtnTxt( tr( "Back" ) , 22, THEME.prompttext );
|
||||
backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
|
||||
GuiImage backBtnImg( &btnOutline );
|
||||
if (Settings.wsprompt == yes) {
|
||||
if ( Settings.wsprompt == yes )
|
||||
{
|
||||
backBtnTxt.SetWidescreen( CFG.widescreen );
|
||||
backBtnImg.SetWidescreen( CFG.widescreen );
|
||||
}
|
||||
@ -297,7 +303,8 @@ int MenuHomebrewBrowse() {
|
||||
MainButton4.SetTrigger( &trigA );
|
||||
|
||||
GuiImage wifiImg( &wifiImgData );
|
||||
if (Settings.wsprompt == yes) {
|
||||
if ( Settings.wsprompt == yes )
|
||||
{
|
||||
wifiImg.SetWidescreen( CFG.widescreen );
|
||||
}
|
||||
GuiButton wifiBtn( wifiImg.GetWidth(), wifiImg.GetHeight() );
|
||||
@ -332,7 +339,8 @@ int MenuHomebrewBrowse() {
|
||||
const int pages = roundup( filecount / 4.0f );
|
||||
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 ();
|
||||
|
||||
menu = MENU_NONE;
|
||||
@ -345,13 +353,16 @@ int MenuHomebrewBrowse() {
|
||||
MainButton3.StopEffect();
|
||||
MainButton4.StopEffect();
|
||||
|
||||
if (slidedirection == RIGHT) {
|
||||
if ( slidedirection == RIGHT )
|
||||
{
|
||||
MainButton1.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 );
|
||||
MainButton4.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
||||
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
||||
} else if (slidedirection == LEFT) {
|
||||
}
|
||||
else if ( slidedirection == LEFT )
|
||||
{
|
||||
MainButton1.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 );
|
||||
@ -364,20 +375,25 @@ int MenuHomebrewBrowse() {
|
||||
mainWindow->RemoveAll();
|
||||
|
||||
/** Set new icons **/
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (IconData[i] != NULL) {
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
if ( IconData[i] != NULL )
|
||||
{
|
||||
delete IconData[i];
|
||||
IconData[i] = NULL;
|
||||
}
|
||||
if (IconImg[i] != NULL) {
|
||||
if ( IconImg[i] != NULL )
|
||||
{
|
||||
delete IconImg[i];
|
||||
IconImg[i] = NULL;
|
||||
}
|
||||
if (fileoffset+i < (int) filecount) {
|
||||
if ( fileoffset + i < ( int ) filecount )
|
||||
{
|
||||
char iconpath[200];
|
||||
snprintf( iconpath, sizeof( iconpath ), "%sicon.png", HomebrewFiles.GetFilepath( fileoffset + i ) );
|
||||
IconData[i] = new GuiImageData( iconpath, 0 );
|
||||
if (IconData[i]->GetImage()) {
|
||||
if ( IconData[i]->GetImage() )
|
||||
{
|
||||
IconImg[i] = new GuiImage( IconData[i] );
|
||||
IconImg[i]->SetAlignment( ALIGN_LEFT, ALIGN_MIDDLE );
|
||||
IconImg[i]->SetPosition( 12, 0 );
|
||||
@ -414,20 +430,25 @@ int MenuHomebrewBrowse() {
|
||||
w.Append( &GoRightBtn );
|
||||
w.Append( &GoLeftBtn );
|
||||
|
||||
if (pageToDisplay == pages) {
|
||||
if ( pageToDisplay == pages )
|
||||
{
|
||||
int buttonsleft = filecount - ( pages - 1 ) * 4;
|
||||
char * shortpath = NULL;
|
||||
char temp[200];
|
||||
|
||||
if (buttonsleft > 0) {
|
||||
if ( buttonsleft > 0 )
|
||||
{
|
||||
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() );
|
||||
MainButton1Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
|
||||
MainButton1DescTxt.SetText( MainButtonText );
|
||||
MainButton1DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
||||
@ -439,15 +460,19 @@ int MenuHomebrewBrowse() {
|
||||
}
|
||||
w.Append( &MainButton1 );
|
||||
}
|
||||
if (buttonsleft > 1) {
|
||||
if ( buttonsleft > 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() );
|
||||
MainButton2Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
|
||||
MainButton2DescTxt.SetText( MainButtonText );
|
||||
MainButton2DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||
@ -459,15 +484,19 @@ int MenuHomebrewBrowse() {
|
||||
}
|
||||
w.Append( &MainButton2 );
|
||||
}
|
||||
if (buttonsleft > 2) {
|
||||
if ( buttonsleft > 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() );
|
||||
MainButton3Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||
MainButton3DescTxt.SetText( MainButtonText );
|
||||
MainButton3DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||
@ -479,15 +508,19 @@ int MenuHomebrewBrowse() {
|
||||
}
|
||||
w.Append( &MainButton3 );
|
||||
}
|
||||
if (buttonsleft > 3) {
|
||||
if ( buttonsleft > 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() );
|
||||
MainButton4Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||
MainButton4DescTxt.SetText( MainButtonText );
|
||||
MainButton4DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||
@ -499,18 +532,23 @@ int MenuHomebrewBrowse() {
|
||||
}
|
||||
w.Append( &MainButton4 );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char temp[200];
|
||||
char *shortpath = NULL;
|
||||
|
||||
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() );
|
||||
MainButton1Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
|
||||
MainButton1DescTxt.SetText( MainButtonText );
|
||||
MainButton1DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
||||
@ -524,13 +562,16 @@ int MenuHomebrewBrowse() {
|
||||
w.Append( &MainButton1 );
|
||||
|
||||
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() );
|
||||
MainButton2Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
|
||||
MainButton2DescTxt.SetText( MainButtonText );
|
||||
MainButton2DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||
@ -544,13 +585,16 @@ int MenuHomebrewBrowse() {
|
||||
w.Append( &MainButton2 );
|
||||
|
||||
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() );
|
||||
MainButton3Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||
MainButton3DescTxt.SetText( MainButtonText );
|
||||
MainButton3DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||
@ -563,13 +607,16 @@ int MenuHomebrewBrowse() {
|
||||
w.Append( &MainButton3 );
|
||||
|
||||
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() );
|
||||
MainButton4Txt.SetText( MainButtonText );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||
MainButton4DescTxt.SetText( MainButtonText );
|
||||
MainButton4DescOverTxt.SetText( MainButtonText );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||
shortpath = strrchr( temp, '/' );
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||
@ -593,17 +640,22 @@ int MenuHomebrewBrowse() {
|
||||
MainButton3.SetEffectGrow();
|
||||
MainButton4.SetEffectGrow();
|
||||
|
||||
if (slidedirection == FADE) {
|
||||
if ( slidedirection == FADE )
|
||||
{
|
||||
MainButton1.SetEffect( EFFECT_FADE, 20 );
|
||||
MainButton2.SetEffect( EFFECT_FADE, 20 );
|
||||
MainButton3.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 );
|
||||
MainButton2.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 );
|
||||
} else if (slidedirection == RIGHT) {
|
||||
}
|
||||
else if ( slidedirection == RIGHT )
|
||||
{
|
||||
MainButton1.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 );
|
||||
@ -616,10 +668,12 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
||||
|
||||
while (!changed) {
|
||||
while ( !changed )
|
||||
{
|
||||
VIDEO_WaitVSync ();
|
||||
|
||||
if (MainButton1.GetState() == STATE_CLICKED) {
|
||||
if ( MainButton1.GetState() == STATE_CLICKED )
|
||||
{
|
||||
char temp[200];
|
||||
char iconpath[200];
|
||||
char metapath[200];
|
||||
@ -639,14 +693,17 @@ int MenuHomebrewBrowse() {
|
||||
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 );
|
||||
if (choice == 1) {
|
||||
if ( choice == 1 )
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset ), HomebrewFiles.GetFilename( fileoffset ) );
|
||||
break;
|
||||
}
|
||||
MainButton1.ResetState();
|
||||
} else if (MainButton2.GetState() == STATE_CLICKED) {
|
||||
}
|
||||
else if ( MainButton2.GetState() == STATE_CLICKED )
|
||||
{
|
||||
char temp[200];
|
||||
char iconpath[200];
|
||||
char metapath[200];
|
||||
@ -666,14 +723,17 @@ int MenuHomebrewBrowse() {
|
||||
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 );
|
||||
if (choice == 1) {
|
||||
if ( choice == 1 )
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 1 ), HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||
break;
|
||||
}
|
||||
MainButton2.ResetState();
|
||||
} else if (MainButton3.GetState() == STATE_CLICKED) {
|
||||
}
|
||||
else if ( MainButton3.GetState() == STATE_CLICKED )
|
||||
{
|
||||
char temp[200];
|
||||
char iconpath[200];
|
||||
char metapath[200];
|
||||
@ -693,14 +753,17 @@ int MenuHomebrewBrowse() {
|
||||
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 );
|
||||
if (choice == 1) {
|
||||
if ( choice == 1 )
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 2 ), HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||
break;
|
||||
}
|
||||
MainButton3.ResetState();
|
||||
} else if (MainButton4.GetState() == STATE_CLICKED) {
|
||||
}
|
||||
else if ( MainButton4.GetState() == STATE_CLICKED )
|
||||
{
|
||||
char temp[200];
|
||||
char iconpath[200];
|
||||
char metapath[200];
|
||||
@ -720,7 +783,8 @@ int MenuHomebrewBrowse() {
|
||||
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 );
|
||||
if (choice == 1) {
|
||||
if ( choice == 1 )
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 3 ), HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||
@ -734,12 +798,14 @@ int MenuHomebrewBrowse() {
|
||||
else if ( reset == 1 )
|
||||
Sys_Reboot();
|
||||
|
||||
else if (backBtn.GetState() == STATE_CLICKED) {
|
||||
else if ( backBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
menu = MENU_DISCLIST;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
else if (GoLeftBtn.GetState() == STATE_CLICKED) {
|
||||
else if ( GoLeftBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
pageToDisplay--;
|
||||
/** Change direction of the flying buttons **/
|
||||
if ( pageToDisplay < 1 )
|
||||
@ -749,7 +815,8 @@ int MenuHomebrewBrowse() {
|
||||
GoLeftBtn.ResetState();
|
||||
}
|
||||
|
||||
else if (GoRightBtn.GetState() == STATE_CLICKED) {
|
||||
else if ( GoRightBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
pageToDisplay++;
|
||||
/** Change direction of the flying buttons **/
|
||||
if ( pageToDisplay > pages )
|
||||
@ -759,28 +826,36 @@ int MenuHomebrewBrowse() {
|
||||
GoRightBtn.ResetState();
|
||||
}
|
||||
|
||||
else if (wifiBtn.GetState() == STATE_CLICKED) {
|
||||
else if ( wifiBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
|
||||
ResumeNetworkWait();
|
||||
wifiBtn.ResetState();
|
||||
}
|
||||
|
||||
else if (homo.GetState() == STATE_CLICKED) {
|
||||
else if ( homo.GetState() == STATE_CLICKED )
|
||||
{
|
||||
cfg_save_global();
|
||||
bgMusic->Pause();
|
||||
choice = WindowExitPrompt();
|
||||
bgMusic->Resume();
|
||||
|
||||
if (choice == 3) {
|
||||
if ( choice == 3 )
|
||||
{
|
||||
Sys_LoadMenu(); // Back to System Menu
|
||||
} else if (choice == 2) {
|
||||
}
|
||||
else if ( choice == 2 )
|
||||
{
|
||||
Sys_BackToLoader();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
homo.ResetState();
|
||||
}
|
||||
}
|
||||
|
||||
else if (infilesize > 0) {
|
||||
else if ( infilesize > 0 )
|
||||
{
|
||||
char filesizetxt[50];
|
||||
char temp[50];
|
||||
|
||||
@ -793,14 +868,18 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
int choice = WindowPrompt( filesizetxt, temp, tr( "OK" ), tr( "Cancel" ) );
|
||||
|
||||
if (choice == 1) {
|
||||
if ( choice == 1 )
|
||||
{
|
||||
|
||||
int res = AllocHomebrewMemory( infilesize );
|
||||
|
||||
if (res < 0) {
|
||||
if ( res < 0 )
|
||||
{
|
||||
CloseConnection();
|
||||
WindowPrompt( tr( "Not enough free memory." ), 0, tr( "OK" ) );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 read = 0;
|
||||
u8 *temp = NULL;
|
||||
int len = NETWORKBLOCKSIZE;
|
||||
@ -808,7 +887,8 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
bool error = false;
|
||||
u8 *ptr = temp;
|
||||
while (read < infilesize) {
|
||||
while ( read < infilesize )
|
||||
{
|
||||
|
||||
ShowProgress( tr( "Receiving file from:" ), GetIncommingIP(), NULL, read, infilesize, true );
|
||||
|
||||
@ -819,12 +899,14 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
int result = network_read( ptr, len );
|
||||
|
||||
if (result < 0) {
|
||||
if ( result < 0 )
|
||||
{
|
||||
WindowPrompt( tr( "Error while transfering data." ), 0, tr( "OK" ) );
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
if (!result) {
|
||||
if ( !result )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@ -834,15 +916,18 @@ int MenuHomebrewBrowse() {
|
||||
}
|
||||
|
||||
char filename[101];
|
||||
if (!error) {
|
||||
if ( !error )
|
||||
{
|
||||
|
||||
network_read( ( u8* ) &filename, 100 );
|
||||
|
||||
// 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...
|
||||
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
|
||||
|
||||
// Zip archive, ask for permission to install the zip
|
||||
@ -857,9 +942,12 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
// Now unzip the zip file...
|
||||
unzFile uf = unzOpen( zippath );
|
||||
if (uf==NULL) {
|
||||
if ( uf == NULL )
|
||||
{
|
||||
error = true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
extractZip( uf, 0, 1, 0, Settings.homebrewapps_path );
|
||||
unzCloseCurrentFile( uf );
|
||||
|
||||
@ -869,10 +957,14 @@ int MenuHomebrewBrowse() {
|
||||
menu = MENU_HOMEBREWBROWSE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
u8 *unc = ( u8 * ) malloc( uncfilesize );
|
||||
uLongf f = uncfilesize;
|
||||
@ -885,7 +977,8 @@ int MenuHomebrewBrowse() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!error && strstr(filename,".zip") == NULL) {
|
||||
if ( !error && strstr( filename, ".zip" ) == NULL )
|
||||
{
|
||||
innetbuffer = temp;
|
||||
|
||||
}
|
||||
@ -893,21 +986,29 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
ProgressStop();
|
||||
|
||||
if (error || read != infilesize) {
|
||||
if ( error || read != infilesize )
|
||||
{
|
||||
WindowPrompt( tr( "Error:" ), tr( "No data could be read." ), tr( "OK" ) );
|
||||
FreeHomebrewBuffer();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( strstr( filename, ".dol" ) || strstr( filename, ".DOL" )
|
||||
|| strstr(filename,".elf") || strstr(filename,".ELF")) {
|
||||
|| strstr( filename, ".elf" ) || strstr( filename, ".ELF" ) )
|
||||
{
|
||||
boothomebrew = 2;
|
||||
AddBootArgument( filename );
|
||||
menu = MENU_EXIT;
|
||||
CloseConnection();
|
||||
break;
|
||||
} else if (strstr(filename,".zip")) {
|
||||
}
|
||||
else if ( strstr( filename, ".zip" ) )
|
||||
{
|
||||
WindowPrompt( tr( "Success:" ), tr( "Uploaded ZIP file installed to homebrew directory." ), tr( "OK" ) );
|
||||
CloseConnection();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeHomebrewBuffer();
|
||||
WindowPrompt( tr( "ERROR:" ), tr( "Not a DOL/ELF file." ), tr( "OK" ) );
|
||||
}
|
||||
@ -918,7 +1019,8 @@ int MenuHomebrewBrowse() {
|
||||
ResumeNetworkWait();
|
||||
}
|
||||
|
||||
else if (channelBtn.GetState() == STATE_CLICKED) {
|
||||
else if ( channelBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
w.SetState( STATE_DISABLED );
|
||||
//10001 are the channels that are installed as channels, not including shop channel/mii channel etc
|
||||
TitleBrowser();
|
||||
@ -929,8 +1031,10 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
}
|
||||
|
||||
if (IsNetworkInit()) {
|
||||
if (!wifi_btn_loaded) {
|
||||
if ( IsNetworkInit() )
|
||||
{
|
||||
if ( !wifi_btn_loaded )
|
||||
{
|
||||
wifiBtn.SetAlpha( 255 );
|
||||
|
||||
titleTT = new GuiTooltip( GetNetworkIP() );
|
||||
@ -947,12 +1051,15 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
HaltGui();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (IconData[i] != NULL) {
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
if ( IconData[i] != NULL )
|
||||
{
|
||||
delete IconData[i];
|
||||
IconData[i] = NULL;
|
||||
}
|
||||
if (IconImg[i] != NULL) {
|
||||
if ( IconImg[i] != NULL )
|
||||
{
|
||||
delete IconImg[i];
|
||||
IconImg[i] = NULL;
|
||||
}
|
||||
|
@ -9,11 +9,13 @@
|
||||
|
||||
#include "HomebrewFiles.h"
|
||||
|
||||
HomebrewFiles::HomebrewFiles(const char * path) {
|
||||
HomebrewFiles::HomebrewFiles( const char * path )
|
||||
{
|
||||
filecount = 0;
|
||||
|
||||
FileInfo = ( FileInfos * ) malloc( sizeof( FileInfos ) );
|
||||
if (!FileInfo) {
|
||||
if ( !FileInfo )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@ -23,42 +25,54 @@ HomebrewFiles::HomebrewFiles(const char * path) {
|
||||
this->SortList();
|
||||
}
|
||||
|
||||
HomebrewFiles::~HomebrewFiles() {
|
||||
if (FileInfo) {
|
||||
HomebrewFiles::~HomebrewFiles()
|
||||
{
|
||||
if ( FileInfo )
|
||||
{
|
||||
free( FileInfo );
|
||||
FileInfo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool HomebrewFiles::LoadPath(const char * folderpath) {
|
||||
bool HomebrewFiles::LoadPath( const char * folderpath )
|
||||
{
|
||||
struct stat st;
|
||||
DIR_ITER *dir = NULL;
|
||||
char filename[1024];
|
||||
|
||||
dir = diropen( folderpath );
|
||||
if (dir == NULL) {
|
||||
if ( dir == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (dirnext(dir,filename,&st) == 0) {
|
||||
if ((st.st_mode & S_IFDIR) != 0) {
|
||||
if (strcmp(filename,".") != 0 && strcmp(filename,"..") != 0) {
|
||||
while ( dirnext( dir, filename, &st ) == 0 )
|
||||
{
|
||||
if ( ( st.st_mode & S_IFDIR ) != 0 )
|
||||
{
|
||||
if ( strcmp( filename, "." ) != 0 && strcmp( filename, ".." ) != 0 )
|
||||
{
|
||||
char currentname[200];
|
||||
snprintf( currentname, sizeof( currentname ), "%s%s/", folderpath, filename );
|
||||
this->LoadPath( currentname );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char temp[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for ( int i = 0; i < 5; i++ )
|
||||
{
|
||||
temp[i] = filename[strlen( filename )-4+i];
|
||||
}
|
||||
|
||||
if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 )
|
||||
&& filecount < MAXHOMEBREWS && filename[0]!='.') {
|
||||
&& filecount < MAXHOMEBREWS && filename[0] != '.' )
|
||||
{
|
||||
|
||||
FileInfo = ( FileInfos * ) realloc( FileInfo, ( filecount + 1 ) * sizeof( FileInfos ) );
|
||||
|
||||
if (!FileInfo) {
|
||||
if ( !FileInfo )
|
||||
{
|
||||
free( FileInfo );
|
||||
FileInfo = NULL;
|
||||
filecount = 0;
|
||||
@ -80,37 +94,43 @@ bool HomebrewFiles::LoadPath(const char * folderpath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char * HomebrewFiles::GetFilename(int ind) {
|
||||
char * HomebrewFiles::GetFilename( int ind )
|
||||
{
|
||||
if ( ind > filecount )
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FileName;
|
||||
}
|
||||
|
||||
char * HomebrewFiles::GetFilepath(int ind) {
|
||||
char * HomebrewFiles::GetFilepath( int ind )
|
||||
{
|
||||
if ( ind > filecount )
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FilePath;
|
||||
}
|
||||
|
||||
unsigned int HomebrewFiles::GetFilesize(int ind) {
|
||||
unsigned int HomebrewFiles::GetFilesize( int ind )
|
||||
{
|
||||
if ( ind > filecount || !filecount || !FileInfo )
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FileSize;
|
||||
}
|
||||
|
||||
int HomebrewFiles::GetFilecount() {
|
||||
int HomebrewFiles::GetFilecount()
|
||||
{
|
||||
return filecount;
|
||||
}
|
||||
|
||||
static int ListCompare(const void *a, const void *b) {
|
||||
static int ListCompare( const void *a, const void *b )
|
||||
{
|
||||
FileInfos *ab = ( FileInfos* ) a;
|
||||
FileInfos *bb = ( FileInfos* ) b;
|
||||
|
||||
return stricmp( ( char * ) ab->FilePath, ( char * ) bb->FilePath );
|
||||
}
|
||||
void HomebrewFiles::SortList() {
|
||||
void HomebrewFiles::SortList()
|
||||
{
|
||||
qsort( FileInfo, filecount, sizeof( FileInfos ), ListCompare );
|
||||
}
|
||||
|
@ -7,13 +7,15 @@
|
||||
|
||||
#define MAXHOMEBREWS 500
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char FileName[100];
|
||||
char FilePath[150];
|
||||
unsigned int FileSize;
|
||||
} FileInfos;
|
||||
|
||||
class HomebrewFiles {
|
||||
class HomebrewFiles
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param path Path where to check for homebrew files
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
#include "dolloader.h"
|
||||
|
||||
typedef struct _dolheader {
|
||||
typedef struct _dolheader
|
||||
{
|
||||
u32 text_pos[7];
|
||||
u32 data_pos[11];
|
||||
u32 text_start[7];
|
||||
@ -20,19 +21,23 @@ typedef struct _dolheader {
|
||||
u32 entry_point;
|
||||
} dolheader;
|
||||
|
||||
u32 load_dol(const void *dolstart, struct __argv *argv) {
|
||||
u32 load_dol( const void *dolstart, struct __argv *argv )
|
||||
{
|
||||
u32 i;
|
||||
dolheader *dolfile;
|
||||
|
||||
if (dolstart) {
|
||||
if ( 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;
|
||||
ICInvalidateRange ( ( void * ) dolfile->text_start[i], dolfile->text_size[i] );
|
||||
memcpy( ( void * ) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i] );
|
||||
}
|
||||
|
||||
for (i = 0; i < 11; i++) {
|
||||
for ( i = 0; i < 11; i++ )
|
||||
{
|
||||
if ( ( !dolfile->data_size[i] ) || ( dolfile->data_start[i] < 0x100 ) ) continue;
|
||||
memcpy( ( void * ) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i] );
|
||||
DCFlushRangeNoSync ( ( void * ) dolfile->data_start[i], dolfile->data_size[i] );
|
||||
@ -41,7 +46,8 @@ u32 load_dol(const void *dolstart, struct __argv *argv) {
|
||||
memset ( ( void * ) dolfile->bss_start, 0, 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 );
|
||||
memcpy( new_argv, argv, sizeof( *argv ) );
|
||||
DCFlushRange( new_argv, sizeof( *argv ) );
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define _DOLLOADER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern void __exception_closeall();
|
||||
|
@ -77,8 +77,10 @@ void SetupPads()
|
||||
* ShutoffRumble
|
||||
***************************************************************************/
|
||||
|
||||
void ShutoffRumble() {
|
||||
for (int i=0;i<4;i++) {
|
||||
void ShutoffRumble()
|
||||
{
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
WPAD_Rumble( i, 0 );
|
||||
rumbleCount[i] = 0;
|
||||
}
|
||||
@ -88,14 +90,20 @@ void ShutoffRumble() {
|
||||
* DoRumble
|
||||
***************************************************************************/
|
||||
|
||||
void DoRumble(int i) {
|
||||
if (rumbleRequest[i] && rumbleCount[i] < 3) {
|
||||
void DoRumble( int i )
|
||||
{
|
||||
if ( rumbleRequest[i] && rumbleCount[i] < 3 )
|
||||
{
|
||||
WPAD_Rumble( i, 1 ); // rumble on
|
||||
rumbleCount[i]++;
|
||||
} else if (rumbleRequest[i]) {
|
||||
}
|
||||
else if ( rumbleRequest[i] )
|
||||
{
|
||||
rumbleCount[i] = 20;
|
||||
rumbleRequest[i] = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rumbleCount[i] )
|
||||
rumbleCount[i]--;
|
||||
WPAD_Rumble( i, 0 ); // rumble off
|
||||
@ -108,25 +116,31 @@ void DoRumble(int i) {
|
||||
* Get X/Y value from Wii Joystick (classic, nunchuk) input
|
||||
***************************************************************************/
|
||||
|
||||
s8 WPAD_Stick(u8 chan, u8 right, int axis) {
|
||||
s8 WPAD_Stick( u8 chan, u8 right, int axis )
|
||||
{
|
||||
float mag = 0.0;
|
||||
float ang = 0.0;
|
||||
WPADData *data = WPAD_Data( chan );
|
||||
|
||||
switch (data->exp.type) {
|
||||
switch ( data->exp.type )
|
||||
{
|
||||
case WPAD_EXP_NUNCHUK:
|
||||
case WPAD_EXP_GUITARHERO3:
|
||||
if (right == 0) {
|
||||
if ( right == 0 )
|
||||
{
|
||||
mag = data->exp.nunchuk.js.mag;
|
||||
ang = data->exp.nunchuk.js.ang;
|
||||
}
|
||||
break;
|
||||
|
||||
case WPAD_EXP_CLASSIC:
|
||||
if (right == 0) {
|
||||
if ( right == 0 )
|
||||
{
|
||||
mag = data->exp.classic.ljs.mag;
|
||||
ang = data->exp.classic.ljs.ang;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
mag = data->exp.classic.rjs.mag;
|
||||
ang = data->exp.classic.rjs.ang;
|
||||
}
|
||||
|
@ -13,7 +13,8 @@
|
||||
#include "network/networkops.h"
|
||||
#include "network/http.h"
|
||||
|
||||
int updateLanguageFiles() {
|
||||
int updateLanguageFiles()
|
||||
{
|
||||
char languageFiles[50][MAXLANGUAGEFILES];
|
||||
|
||||
//get all the files in the language path
|
||||
@ -23,10 +24,12 @@ int updateLanguageFiles() {
|
||||
if ( !countfiles ) return -2;
|
||||
|
||||
//now from the files we got, get only the .lang files
|
||||
for (int cnt = 0; cnt < countfiles; cnt++) {
|
||||
for ( int cnt = 0; cnt < countfiles; cnt++ )
|
||||
{
|
||||
char filename[64];
|
||||
strlcpy( filename, GetFileName( cnt ), sizeof( filename ) );
|
||||
if (strcasestr(filename,".lang")) {
|
||||
if ( strcasestr( filename, ".lang" ) )
|
||||
{
|
||||
strcpy( languageFiles[cnt], filename );
|
||||
}
|
||||
}
|
||||
@ -36,9 +39,11 @@ int updateLanguageFiles() {
|
||||
//we assume that the network will already be init by another function
|
||||
// ( that has gui eletents in it because this one doesn't)
|
||||
int done = 0, j = 0;
|
||||
if (IsNetworkInit()) {
|
||||
if ( IsNetworkInit() )
|
||||
{
|
||||
//build the URL, save path, and download each file and save it
|
||||
while (j<countfiles) {
|
||||
while ( j < countfiles )
|
||||
{
|
||||
char savepath[150];
|
||||
char codeurl[200];
|
||||
snprintf( codeurl, sizeof( codeurl ), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s", languageFiles[j] );
|
||||
@ -46,10 +51,12 @@ int updateLanguageFiles() {
|
||||
|
||||
struct block file = downloadfile( codeurl );
|
||||
|
||||
if (file.data != NULL) {
|
||||
if ( file.data != NULL )
|
||||
{
|
||||
FILE * pfile;
|
||||
pfile = fopen( savepath, "wb" );
|
||||
if(pfile != NULL) {
|
||||
if ( pfile != NULL )
|
||||
{
|
||||
fwrite( file.data, 1, file.size, pfile );
|
||||
fclose( pfile );
|
||||
free( file.data );
|
||||
|
@ -4,7 +4,8 @@
|
||||
#include <gctypes.h>
|
||||
#include "gettext.h"
|
||||
|
||||
typedef struct _MSG {
|
||||
typedef struct _MSG
|
||||
{
|
||||
u32 id;
|
||||
char* msgstr;
|
||||
struct _MSG *next;
|
||||
@ -18,17 +19,20 @@ static MSG *baseMSG=0;
|
||||
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
||||
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
||||
static inline u32
|
||||
hash_string (const char *str_param) {
|
||||
hash_string ( const char *str_param )
|
||||
{
|
||||
u32 hval, g;
|
||||
const char *str = str_param;
|
||||
|
||||
/* Compute the hash value for the given string. */
|
||||
hval = 0;
|
||||
while (*str != '\0') {
|
||||
while ( *str != '\0' )
|
||||
{
|
||||
hval <<= 4;
|
||||
hval += ( u8 ) * str++;
|
||||
g = hval & ( ( u32 ) 0xf << ( HASHWORDBITS - 4 ) );
|
||||
if (g != 0) {
|
||||
if ( g != 0 )
|
||||
{
|
||||
hval ^= g >> ( HASHWORDBITS - 8 );
|
||||
hval ^= g;
|
||||
}
|
||||
@ -38,7 +42,8 @@ hash_string (const char *str_param) {
|
||||
|
||||
/* Expand some escape sequences found in the argument string. */
|
||||
static char *
|
||||
expand_escape (const char *str) {
|
||||
expand_escape ( const char *str )
|
||||
{
|
||||
char *retval, *rp;
|
||||
const char *cp = str;
|
||||
|
||||
@ -50,10 +55,12 @@ expand_escape (const char *str) {
|
||||
*rp++ = *cp++;
|
||||
if ( cp[0] == '\0' )
|
||||
goto terminate;
|
||||
do {
|
||||
do
|
||||
{
|
||||
|
||||
/* Here cp[0] == '\\'. */
|
||||
switch (*++cp) {
|
||||
switch ( *++cp )
|
||||
{
|
||||
case '\"': /* " */
|
||||
*rp++ = '\"';
|
||||
++cp;
|
||||
@ -97,14 +104,17 @@ expand_escape (const char *str) {
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7': {
|
||||
case '7':
|
||||
{
|
||||
int ch = *cp++ - '0';
|
||||
|
||||
if (*cp >= '0' && *cp <= '7') {
|
||||
if ( *cp >= '0' && *cp <= '7' )
|
||||
{
|
||||
ch *= 8;
|
||||
ch += *cp++ - '0';
|
||||
|
||||
if (*cp >= '0' && *cp <= '7') {
|
||||
if ( *cp >= '0' && *cp <= '7' )
|
||||
{
|
||||
ch *= 8;
|
||||
ch += *cp++ - '0';
|
||||
}
|
||||
@ -119,7 +129,8 @@ expand_escape (const char *str) {
|
||||
|
||||
while ( cp[0] != '\0' && cp[0] != '\\' )
|
||||
*rp++ = *cp++;
|
||||
} while (cp[0] != '\0');
|
||||
}
|
||||
while ( cp[0] != '\0' );
|
||||
|
||||
/* Terminate string. */
|
||||
terminate:
|
||||
@ -127,27 +138,33 @@ terminate:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static MSG *findMSG(u32 id) {
|
||||
static MSG *findMSG( u32 id )
|
||||
{
|
||||
MSG *msg;
|
||||
for (msg=baseMSG; msg; msg=msg->next) {
|
||||
for ( msg = baseMSG; msg; msg = msg->next )
|
||||
{
|
||||
if ( msg->id == id )
|
||||
return msg;
|
||||
}
|
||||
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 );
|
||||
MSG *msg = findMSG( id );
|
||||
if (!msg) {
|
||||
if ( !msg )
|
||||
{
|
||||
msg = ( MSG * )malloc( sizeof( MSG ) );
|
||||
msg->id = id;
|
||||
msg->msgstr = NULL;
|
||||
msg->next = baseMSG;
|
||||
baseMSG = msg;
|
||||
}
|
||||
if (msg) {
|
||||
if (msgstr) {
|
||||
if ( msg )
|
||||
{
|
||||
if ( msgstr )
|
||||
{
|
||||
if ( msg->msgstr ) free( msg->msgstr );
|
||||
//msg->msgstr = strdup(msgstr);
|
||||
msg->msgstr = expand_escape( msgstr );
|
||||
@ -156,8 +173,10 @@ static MSG *setMSG(const char *msgid, const char *msgstr) {
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void gettextCleanUp(void) {
|
||||
while (baseMSG) {
|
||||
void gettextCleanUp( void )
|
||||
{
|
||||
while ( baseMSG )
|
||||
{
|
||||
MSG *nextMsg = baseMSG->next;
|
||||
free( baseMSG->msgstr );
|
||||
free( baseMSG );
|
||||
@ -166,7 +185,8 @@ void gettextCleanUp(void) {
|
||||
}
|
||||
|
||||
|
||||
bool gettextLoadLanguage(const char* langFile) {
|
||||
bool gettextLoadLanguage( const char* langFile )
|
||||
{
|
||||
FILE *f;
|
||||
char line[200];
|
||||
char *lastID = NULL;
|
||||
@ -176,23 +196,29 @@ bool gettextLoadLanguage(const char* langFile) {
|
||||
if ( !f )
|
||||
return false;
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
while ( fgets( line, sizeof( line ), f ) )
|
||||
{
|
||||
// lines starting with # are comments
|
||||
if ( line[0] == '#' )
|
||||
continue;
|
||||
else if (strncmp(line, "msgid \"", 7) == 0) {
|
||||
else if ( strncmp( line, "msgid \"", 7 ) == 0 )
|
||||
{
|
||||
char *msgid, *end;
|
||||
if (lastID) {
|
||||
if ( lastID )
|
||||
{
|
||||
free( lastID );
|
||||
lastID = NULL;
|
||||
}
|
||||
msgid = &line[7];
|
||||
end = strrchr( msgid, '"' );
|
||||
if (end && end-msgid>1) {
|
||||
if ( end && end - msgid > 1 )
|
||||
{
|
||||
*end = 0;
|
||||
lastID = strdup( msgid );
|
||||
}
|
||||
} else if (strncmp(line, "msgstr \"", 8) == 0) {
|
||||
}
|
||||
else if ( strncmp( line, "msgstr \"", 8 ) == 0 )
|
||||
{
|
||||
char *msgstr, *end;
|
||||
|
||||
if ( lastID == NULL )
|
||||
@ -200,7 +226,8 @@ bool gettextLoadLanguage(const char* langFile) {
|
||||
|
||||
msgstr = &line[8];
|
||||
end = strrchr( msgstr, '"' );
|
||||
if (end && end-msgstr>1) {
|
||||
if ( end && end - msgstr > 1 )
|
||||
{
|
||||
*end = 0;
|
||||
setMSG( lastID, msgstr );
|
||||
}
|
||||
@ -213,7 +240,8 @@ bool gettextLoadLanguage(const char* langFile) {
|
||||
fclose( f );
|
||||
return true;
|
||||
}
|
||||
const char *gettext(const char *msgid) {
|
||||
const char *gettext( const char *msgid )
|
||||
{
|
||||
MSG *msg = findMSG( hash_string( msgid ) );
|
||||
if ( msg && msg->msgstr ) return msg->msgstr;
|
||||
return msgid;
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define _GETTEXT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -34,20 +34,24 @@
|
||||
/*-----------------------------------------------------------------
|
||||
Functions to deal with little endian values stored in uint8_t arrays
|
||||
-----------------------------------------------------------------*/
|
||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
||||
static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
||||
}
|
||||
|
||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
||||
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
||||
}
|
||||
|
||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
||||
static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
}
|
||||
|
||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
||||
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
||||
|
@ -42,7 +42,8 @@
|
||||
#define PAGE_SECTORS 64
|
||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
@ -50,7 +51,8 @@ typedef struct {
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
@ -99,14 +101,16 @@ bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void*
|
||||
/*
|
||||
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 );
|
||||
}
|
||||
|
||||
/*
|
||||
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 );
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -59,13 +59,15 @@
|
||||
|
||||
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cluster;
|
||||
sec_t sector;
|
||||
int32_t offset;
|
||||
} DIR_ENTRY_POSITION;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
||||
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
|
||||
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
|
||||
@ -73,7 +75,8 @@ typedef struct {
|
||||
} DIR_ENTRY;
|
||||
|
||||
// Directory entry offsets
|
||||
enum DIR_ENTRY_offset {
|
||||
enum DIR_ENTRY_offset
|
||||
{
|
||||
DIR_ENTRY_name = 0x00,
|
||||
DIR_ENTRY_extension = 0x08,
|
||||
DIR_ENTRY_attributes = 0x0B,
|
||||
@ -92,15 +95,18 @@ enum DIR_ENTRY_offset {
|
||||
/*
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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' ) ||
|
||||
( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) );
|
||||
}
|
||||
|
@ -35,7 +35,8 @@
|
||||
A list of all default devices to try at startup,
|
||||
terminated by a {NULL,NULL} entry.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const DISC_INTERFACE* ( *getInterface )( void );
|
||||
} INTERFACE_ID;
|
||||
@ -45,7 +46,8 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
Check if a disc is inserted
|
||||
Return true if a disc is inserted and ready, false otherwise
|
||||
*/
|
||||
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->isInserted();
|
||||
}
|
||||
|
||||
@ -56,7 +58,8 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to fill
|
||||
*/
|
||||
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) {
|
||||
static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
|
||||
{
|
||||
return disc->readSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
@ -67,21 +70,24 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to read from
|
||||
*/
|
||||
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) {
|
||||
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
{
|
||||
return disc->writeSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
Reset the card back to a ready state
|
||||
*/
|
||||
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->clearStatus();
|
||||
}
|
||||
|
||||
/*
|
||||
Initialise the disc to a state ready for data reading or writing
|
||||
*/
|
||||
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->startup();
|
||||
}
|
||||
|
||||
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
Put the disc in a state ready for power down.
|
||||
Complete any pending writes and disable the disc if necessary
|
||||
*/
|
||||
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value unique to each type of interface
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) {
|
||||
static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->ioType;
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value that specifies the capabilities of the disc
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) {
|
||||
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->features;
|
||||
}
|
||||
|
||||
|
@ -43,21 +43,26 @@ The list is terminated by a NULL/NULL entry.
|
||||
#include "usbloader/usbstorage2.h"
|
||||
#include <sdcard/gcsd.h>
|
||||
|
||||
static const DISC_INTERFACE* get_io_wiisd (void) {
|
||||
static const DISC_INTERFACE* get_io_wiisd ( void )
|
||||
{
|
||||
return &__io_wiisd;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_usbstorage (void) {
|
||||
static const DISC_INTERFACE* get_io_usbstorage ( void )
|
||||
{
|
||||
return &__io_usbstorage2;
|
||||
}
|
||||
|
||||
static const DISC_INTERFACE* get_io_gcsda (void) {
|
||||
static const DISC_INTERFACE* get_io_gcsda ( void )
|
||||
{
|
||||
return &__io_gcsda;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_gcsdb (void) {
|
||||
static const DISC_INTERFACE* get_io_gcsdb ( void )
|
||||
{
|
||||
return &__io_gcsdb;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] =
|
||||
{
|
||||
{"sd", get_io_wiisd},
|
||||
{"usb", get_io_usbstorage},
|
||||
{"carda", get_io_gcsda},
|
||||
|
@ -35,7 +35,8 @@
|
||||
A list of all default devices to try at startup,
|
||||
terminated by a {NULL,NULL} entry.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const DISC_INTERFACE* ( *getInterface )( void );
|
||||
} INTERFACE_ID;
|
||||
@ -45,7 +46,8 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
Check if a disc is inserted
|
||||
Return true if a disc is inserted and ready, false otherwise
|
||||
*/
|
||||
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->isInserted();
|
||||
}
|
||||
|
||||
@ -56,7 +58,8 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to fill
|
||||
*/
|
||||
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) {
|
||||
static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
|
||||
{
|
||||
return disc->readSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
@ -67,21 +70,24 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to read from
|
||||
*/
|
||||
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) {
|
||||
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
{
|
||||
return disc->writeSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
Reset the card back to a ready state
|
||||
*/
|
||||
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->clearStatus();
|
||||
}
|
||||
|
||||
/*
|
||||
Initialise the disc to a state ready for data reading or writing
|
||||
*/
|
||||
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->startup();
|
||||
}
|
||||
|
||||
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
Put the disc in a state ready for power down.
|
||||
Complete any pending writes and disable the disc if necessary
|
||||
*/
|
||||
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) {
|
||||
static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value unique to each type of interface
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) {
|
||||
static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->ioType;
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value that specifies the capabilities of the disc
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) {
|
||||
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->features;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,8 @@
|
||||
#define _LIBFAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -46,21 +46,25 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition) {
|
||||
CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition )
|
||||
{
|
||||
CACHE* cache;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if (numberOfPages < 2) {
|
||||
if ( numberOfPages < 2 )
|
||||
{
|
||||
numberOfPages = 2;
|
||||
}
|
||||
|
||||
if (sectorsPerPage < 8) {
|
||||
if ( sectorsPerPage < 8 )
|
||||
{
|
||||
sectorsPerPage = 8;
|
||||
}
|
||||
|
||||
cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) );
|
||||
if (cache == NULL) {
|
||||
if ( cache == 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 );
|
||||
if (cacheEntries == NULL) {
|
||||
if ( cacheEntries == NULL )
|
||||
{
|
||||
_FAT_mem_free ( cache );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numberOfPages; i++) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
@ -89,13 +95,15 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsP
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache) {
|
||||
void _FAT_cache_destructor ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
// Clear out cache before destroying it
|
||||
_FAT_cache_flush( cache );
|
||||
|
||||
// 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 );
|
||||
@ -105,7 +113,8 @@ void _FAT_cache_destructor (CACHE* cache) {
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
static u32 accessTime()
|
||||
{
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
@ -122,20 +131,24 @@ static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector)
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
||||
{
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &( cacheEntries[i] );
|
||||
}
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
||||
{
|
||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
||||
{
|
||||
if ( !_FAT_disc_writeSectors( cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
@ -160,7 +173,8 @@ bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buf
|
||||
CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
|
||||
while(numSectors>0) {
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _FAT_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
@ -197,11 +211,13 @@ bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, uns
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
bool _FAT_cache_readLittleEndianValue ( CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if ( !_FAT_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||
|
||||
switch(num_bytes) {
|
||||
switch ( num_bytes )
|
||||
{
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
@ -230,10 +246,12 @@ bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sect
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
||||
{
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
|
||||
switch(size) {
|
||||
switch ( size )
|
||||
{
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||
@ -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;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
@ -273,16 +292,22 @@ static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count)
|
||||
CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||
{
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
if ( sector > cacheEntries[i].sector )
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
@ -303,9 +328,11 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
|
||||
{
|
||||
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;
|
||||
|
||||
@ -328,7 +355,9 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
|
||||
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_FAT_disc_writeSectors( cache->disc, sector, numSectors, src );
|
||||
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.
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache) {
|
||||
bool _FAT_cache_flush ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
if (cache->cacheEntries[i].dirty) {
|
||||
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
if ( cache->cacheEntries[i].dirty )
|
||||
{
|
||||
if ( !_FAT_disc_writeSectors ( cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -354,10 +387,12 @@ bool _FAT_cache_flush (CACHE* cache) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void _FAT_cache_invalidate (CACHE* cache) {
|
||||
void _FAT_cache_invalidate ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
_FAT_cache_flush( cache );
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
|
@ -42,7 +42,8 @@
|
||||
#define PAGE_SECTORS 64
|
||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
@ -50,7 +51,8 @@ typedef struct {
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
@ -99,14 +101,16 @@ bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void*
|
||||
/*
|
||||
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 );
|
||||
}
|
||||
|
||||
/*
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -45,22 +45,26 @@
|
||||
#include "lock.h"
|
||||
|
||||
|
||||
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
|
||||
int _FAT_stat_r ( struct _reent *r, const char *path, struct stat *st )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
DIR_ENTRY dirEntry;
|
||||
|
||||
// Get the partition this file is on
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if (partition == NULL) {
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -68,7 +72,8 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// 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 );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
@ -81,12 +86,14 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink) {
|
||||
int _FAT_link_r ( struct _reent *r, const char *existing, const char *newLink )
|
||||
{
|
||||
r->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _FAT_unlink_r (struct _reent *r, const char *path) {
|
||||
int _FAT_unlink_r ( struct _reent *r, const char *path )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
DIR_ENTRY dirEntry;
|
||||
DIR_ENTRY dirContents;
|
||||
@ -96,22 +103,26 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
|
||||
|
||||
// Get the partition this directory is on
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if (partition == NULL) {
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure we aren't trying to write to a read-only disc
|
||||
if (partition->readOnly) {
|
||||
if ( partition->readOnly )
|
||||
{
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -119,7 +130,8 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// 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 );
|
||||
r->_errno = ENOENT;
|
||||
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 (_FAT_directory_isDirectory (&dirEntry)) {
|
||||
if ( _FAT_directory_isDirectory ( &dirEntry ) )
|
||||
{
|
||||
nextEntry = _FAT_directory_getFirstEntry ( partition, &dirContents, cluster );
|
||||
|
||||
while (nextEntry) {
|
||||
if (!_FAT_directory_isDot (&dirContents)) {
|
||||
while ( nextEntry )
|
||||
{
|
||||
if ( !_FAT_directory_isDot ( &dirContents ) )
|
||||
{
|
||||
// The directory had something in it that isn't a reference to itself or it's parent
|
||||
_FAT_unlock( &partition->lock );
|
||||
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
|
||||
if (!_FAT_fat_clearLinks (partition, cluster)) {
|
||||
if ( !_FAT_fat_clearLinks ( partition, cluster ) )
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the directory entry for this file
|
||||
if (!_FAT_directory_removeEntry (partition, &dirEntry)) {
|
||||
if ( !_FAT_directory_removeEntry ( partition, &dirEntry ) )
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush(partition->cache)) {
|
||||
if ( !_FAT_cache_flush( partition->cache ) )
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
_FAT_unlock( &partition->lock );
|
||||
if (errorOccured) {
|
||||
if ( errorOccured )
|
||||
{
|
||||
return -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int _FAT_chdir_r (struct _reent *r, const char *path) {
|
||||
int _FAT_chdir_r ( struct _reent *r, const char *path )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
|
||||
// Get the partition this directory is on
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if (partition == NULL) {
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -193,11 +219,14 @@ int _FAT_chdir_r (struct _reent *r, const char *path) {
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Try changing directory
|
||||
if (_FAT_directory_chdir (partition, path)) {
|
||||
if ( _FAT_directory_chdir ( partition, path ) )
|
||||
{
|
||||
// Successful
|
||||
_FAT_unlock( &partition->lock );
|
||||
return 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed
|
||||
_FAT_unlock( &partition->lock );
|
||||
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;
|
||||
DIR_ENTRY oldDirEntry;
|
||||
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
|
||||
partition = _FAT_partition_getPartitionFromPath ( oldName );
|
||||
if (partition == NULL) {
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -222,46 +253,54 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// 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 );
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure we aren't trying to write to a read-only disc
|
||||
if (partition->readOnly) {
|
||||
if ( partition->readOnly )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (oldName, ':') != NULL) {
|
||||
if ( strchr ( oldName, ':' ) != NULL )
|
||||
{
|
||||
oldName = strchr ( oldName, ':' ) + 1;
|
||||
}
|
||||
if (strchr (oldName, ':') != NULL) {
|
||||
if ( strchr ( oldName, ':' ) != NULL )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (strchr (newName, ':') != NULL) {
|
||||
if ( strchr ( newName, ':' ) != NULL )
|
||||
{
|
||||
newName = strchr ( newName, ':' ) + 1;
|
||||
}
|
||||
if (strchr (newName, ':') != NULL) {
|
||||
if ( strchr ( newName, ':' ) != NULL )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Search for the file on the disc
|
||||
if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL)) {
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &oldDirEntry, oldName, NULL ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure there is no existing file / directory with the new name
|
||||
if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL)) {
|
||||
if ( _FAT_directory_entryFromPath ( partition, &newDirEntry, newName, NULL ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
@ -270,15 +309,19 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
||||
// Create the new file entry
|
||||
// Get the directory it has to go in
|
||||
pathEnd = strrchr ( newName, DIR_SEPARATOR );
|
||||
if (pathEnd == NULL) {
|
||||
if ( pathEnd == NULL )
|
||||
{
|
||||
// No path was specified
|
||||
dirCluster = partition->cwdCluster;
|
||||
pathEnd = newName;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Path was specified -- get the right dirCluster
|
||||
// Recycling newDirEntry, since it needs to be recreated anyway
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) ||
|
||||
!_FAT_directory_isDirectory(&newDirEntry)) {
|
||||
!_FAT_directory_isDirectory( &newDirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOTDIR;
|
||||
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 );
|
||||
|
||||
// Write the new entry
|
||||
if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster)) {
|
||||
if ( !_FAT_directory_addEntry ( partition, &newDirEntry, dirCluster ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Remove the old entry
|
||||
if (!_FAT_directory_removeEntry (partition, &oldDirEntry)) {
|
||||
if ( !_FAT_directory_removeEntry ( partition, &oldDirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush (partition->cache)) {
|
||||
if ( !_FAT_cache_flush ( partition->cache ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
@ -319,7 +365,8 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
||||
int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
bool fileExists;
|
||||
DIR_ENTRY dirEntry;
|
||||
@ -328,16 +375,19 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
||||
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
||||
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if (partition == NULL) {
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
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 );
|
||||
|
||||
// Make sure it doesn't exist
|
||||
if (fileExists) {
|
||||
if ( fileExists )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (partition->readOnly) {
|
||||
if ( partition->readOnly )
|
||||
{
|
||||
// We can't write to a read-only partition
|
||||
_FAT_unlock( &partition->lock );
|
||||
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
|
||||
pathEnd = strrchr ( path, DIR_SEPARATOR );
|
||||
if (pathEnd == NULL) {
|
||||
if ( pathEnd == NULL )
|
||||
{
|
||||
// No path was specified
|
||||
parentCluster = partition->cwdCluster;
|
||||
pathEnd = path;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Path was specified -- get the right parentCluster
|
||||
// Recycling dirEntry, since it needs to be recreated anyway
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
|
||||
!_FAT_directory_isDirectory(&dirEntry)) {
|
||||
!_FAT_directory_isDirectory( &dirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOTDIR;
|
||||
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
|
||||
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
|
||||
_FAT_unlock( &partition->lock );
|
||||
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 );
|
||||
|
||||
// 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 );
|
||||
r->_errno = ENOSPC;
|
||||
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 );
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush(partition->cache)) {
|
||||
if ( !_FAT_cache_flush( partition->cache ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EIO;
|
||||
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
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if (partition == NULL) {
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -493,22 +553,26 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) {
|
||||
DIR_ITER* _FAT_diropen_r( struct _reent *r, DIR_ITER *dirState, const char *path )
|
||||
{
|
||||
DIR_ENTRY dirEntry;
|
||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||
bool fileExists;
|
||||
|
||||
state->partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if (state->partition == NULL) {
|
||||
if ( state->partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
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
|
||||
fileExists = _FAT_directory_entryFromPath ( state->partition, &dirEntry, path, NULL );
|
||||
|
||||
if (!fileExists) {
|
||||
if ( !fileExists )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Make sure it is a directory
|
||||
if (! _FAT_directory_isDirectory (&dirEntry)) {
|
||||
if ( ! _FAT_directory_isDirectory ( &dirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = ENOTDIR;
|
||||
return NULL;
|
||||
@ -544,13 +610,15 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
|
||||
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 );
|
||||
|
||||
_FAT_lock( &state->partition->lock );
|
||||
|
||||
// Make sure we are still using this entry
|
||||
if (!state->inUse) {
|
||||
if ( !state->inUse )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
@ -564,20 +632,23 @@ int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) {
|
||||
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 );
|
||||
|
||||
_FAT_lock( &state->partition->lock );
|
||||
|
||||
// Make sure we are still using this entry
|
||||
if (!state->inUse) {
|
||||
if ( !state->inUse )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure there is another file to report on
|
||||
if (! state->validEntry) {
|
||||
if ( ! state->validEntry )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
@ -586,7 +657,8 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
// Get the filename
|
||||
strncpy ( filename, state->currentEntry.filename, MAX_FILENAME_LENGTH );
|
||||
// Get the stats, if requested
|
||||
if (filestat != NULL) {
|
||||
if ( filestat != NULL )
|
||||
{
|
||||
_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;
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
// We are no longer using this entry
|
||||
|
@ -39,7 +39,8 @@
|
||||
#include "common.h"
|
||||
#include "directory.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
PARTITION* partition;
|
||||
DIR_ENTRY currentEntry;
|
||||
uint32_t startCluster;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,7 +41,8 @@
|
||||
|
||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 cluster;
|
||||
sec_t sector;
|
||||
s32 byte;
|
||||
@ -49,7 +50,8 @@ typedef struct {
|
||||
|
||||
struct _FILE_STRUCT;
|
||||
|
||||
struct _FILE_STRUCT {
|
||||
struct _FILE_STRUCT
|
||||
{
|
||||
uint32_t filesize;
|
||||
uint32_t startCluster;
|
||||
uint32_t currentPosition;
|
||||
|
@ -41,7 +41,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||
sec_t sector;
|
||||
int offset;
|
||||
|
||||
if (cluster == CLUSTER_FREE) {
|
||||
if ( cluster == CLUSTER_FREE )
|
||||
{
|
||||
return CLUSTER_FREE;
|
||||
}
|
||||
|
||||
@ -62,7 +63,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||
|
||||
offset++;
|
||||
|
||||
if (offset >= BYTES_PER_READ) {
|
||||
if ( offset >= BYTES_PER_READ )
|
||||
{
|
||||
offset = 0;
|
||||
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 ) );
|
||||
nextCluster |= ( nextCluster_h << 8 );
|
||||
|
||||
if (cluster & 0x01) {
|
||||
if ( cluster & 0x01 )
|
||||
{
|
||||
nextCluster = nextCluster >> 4;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
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 ) );
|
||||
|
||||
if (nextCluster >= 0xFFF7) {
|
||||
if ( nextCluster >= 0xFFF7 )
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
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 ) );
|
||||
|
||||
if (nextCluster >= 0x0FFFFFF7) {
|
||||
if ( nextCluster >= 0x0FFFFFF7 )
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
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
|
||||
on the cluster number.
|
||||
*/
|
||||
static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value) {
|
||||
static bool _FAT_fat_writeFatEntry ( PARTITION* partition, uint32_t cluster, uint32_t value )
|
||||
{
|
||||
sec_t sector;
|
||||
int offset;
|
||||
uint32_t oldValue;
|
||||
@ -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 );
|
||||
offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ;
|
||||
|
||||
if (cluster & 0x01) {
|
||||
if ( cluster & 0x01 )
|
||||
{
|
||||
|
||||
_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 ) );
|
||||
|
||||
offset++;
|
||||
if (offset >= BYTES_PER_READ) {
|
||||
if ( offset >= BYTES_PER_READ )
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, ( value >> 8 ) & 0xFF, sector, offset, sizeof( u8 ) );
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) );
|
||||
|
||||
offset++;
|
||||
if (offset >= BYTES_PER_READ) {
|
||||
if ( offset >= BYTES_PER_READ )
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
@ -203,7 +216,8 @@ to end of file, links the input cluster to it then returns the
|
||||
cluster number
|
||||
If an error occurs, return CLUSTER_ERROR
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
|
||||
uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t firstFree;
|
||||
uint32_t curLink;
|
||||
uint32_t lastCluster;
|
||||
@ -211,32 +225,40 @@ uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
|
||||
|
||||
lastCluster = partition->fat.lastCluster;
|
||||
|
||||
if (cluster > lastCluster) {
|
||||
if ( cluster > lastCluster )
|
||||
{
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
|
||||
// Check if the cluster already has a link, and return it if so
|
||||
curLink = _FAT_fat_nextCluster( partition, cluster );
|
||||
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster)) {
|
||||
if ( ( curLink >= CLUSTER_FIRST ) && ( curLink <= lastCluster ) )
|
||||
{
|
||||
return curLink; // Return the current link - don't allocate a new one
|
||||
}
|
||||
|
||||
// Get a free cluster
|
||||
firstFree = partition->fat.firstFree;
|
||||
// Start at first valid cluster
|
||||
if (firstFree < CLUSTER_FIRST) {
|
||||
if ( firstFree < CLUSTER_FIRST )
|
||||
{
|
||||
firstFree = CLUSTER_FIRST;
|
||||
}
|
||||
|
||||
// Search until a free cluster is found
|
||||
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) {
|
||||
while ( _FAT_fat_nextCluster( partition, firstFree ) != CLUSTER_FREE )
|
||||
{
|
||||
firstFree++;
|
||||
if (firstFree > lastCluster) {
|
||||
if (loopedAroundFAT) {
|
||||
if ( firstFree > lastCluster )
|
||||
{
|
||||
if ( loopedAroundFAT )
|
||||
{
|
||||
// If couldn't get a free cluster then return an error
|
||||
partition->fat.firstFree = firstFree;
|
||||
return CLUSTER_ERROR;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try looping back to the beginning of the FAT
|
||||
// This was suggested by loopy
|
||||
firstFree = CLUSTER_FIRST;
|
||||
@ -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
|
||||
If an error occurs, return CLUSTER_ERROR
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster) {
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t newCluster;
|
||||
uint32_t i;
|
||||
uint8_t emptySector[BYTES_PER_READ];
|
||||
@ -271,13 +294,15 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster
|
||||
// Link the cluster
|
||||
newCluster = _FAT_fat_linkFreeCluster( partition, cluster );
|
||||
|
||||
if (newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR) {
|
||||
if ( newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR )
|
||||
{
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
|
||||
// Clear all the sectors within the cluster
|
||||
memset ( emptySector, 0, BYTES_PER_READ );
|
||||
for (i = 0; i < partition->sectorsPerCluster; i++) {
|
||||
for ( i = 0; i < partition->sectorsPerCluster; i++ )
|
||||
{
|
||||
_FAT_cache_writeSectors ( partition->cache,
|
||||
_FAT_fat_clusterToSector ( partition, newCluster ) + i,
|
||||
1, emptySector );
|
||||
@ -291,18 +316,21 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster
|
||||
_FAT_fat_clearLinks
|
||||
frees any cluster used by a file
|
||||
-----------------------------------------------------------------*/
|
||||
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster) {
|
||||
bool _FAT_fat_clearLinks ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
|
||||
return false;
|
||||
|
||||
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
||||
if (cluster < partition->fat.firstFree) {
|
||||
if ( cluster < partition->fat.firstFree )
|
||||
{
|
||||
partition->fat.firstFree = cluster;
|
||||
}
|
||||
|
||||
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR)) {
|
||||
while ( ( cluster != CLUSTER_EOF ) && ( cluster != CLUSTER_FREE ) && ( cluster != CLUSTER_ERROR ) )
|
||||
{
|
||||
// Store next cluster before erasing the link
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, cluster );
|
||||
|
||||
@ -324,25 +352,31 @@ If chainLength is 1, the first cluster is kept and the rest are
|
||||
dropped, and so on.
|
||||
Return the last cluster left in the chain.
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength) {
|
||||
uint32_t _FAT_fat_trimChain ( PARTITION* partition, uint32_t startCluster, unsigned int chainLength )
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if (chainLength == 0) {
|
||||
if ( chainLength == 0 )
|
||||
{
|
||||
// Drop the entire chain
|
||||
_FAT_fat_clearLinks ( partition, startCluster );
|
||||
return CLUSTER_FREE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the last cluster in the chain, and the one after it
|
||||
chainLength--;
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
||||
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) {
|
||||
while ( ( chainLength > 0 ) && ( nextCluster != CLUSTER_FREE ) && ( nextCluster != CLUSTER_EOF ) )
|
||||
{
|
||||
chainLength--;
|
||||
startCluster = nextCluster;
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
||||
}
|
||||
|
||||
// Drop all clusters after the last in the chain
|
||||
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF) {
|
||||
if ( nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF )
|
||||
{
|
||||
_FAT_fat_clearLinks ( partition, nextCluster );
|
||||
}
|
||||
|
||||
@ -357,8 +391,10 @@ uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsign
|
||||
_FAT_fat_lastCluster
|
||||
Trace the cluster links until the last one is found
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
|
||||
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF)) {
|
||||
uint32_t _FAT_fat_lastCluster ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
while ( ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_FREE ) && ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_EOF ) )
|
||||
{
|
||||
cluster = _FAT_fat_nextCluster( partition, cluster );
|
||||
}
|
||||
return cluster;
|
||||
@ -368,12 +404,15 @@ uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
|
||||
_FAT_fat_freeClusterCount
|
||||
Return the number of free clusters available
|
||||
-----------------------------------------------------------------*/
|
||||
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition) {
|
||||
unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition )
|
||||
{
|
||||
unsigned int count = 0;
|
||||
uint32_t curCluster;
|
||||
|
||||
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++) {
|
||||
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE) {
|
||||
for ( curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++ )
|
||||
{
|
||||
if ( _FAT_fat_nextCluster( partition, curCluster ) == CLUSTER_FREE )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -57,13 +57,15 @@ uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster);
|
||||
|
||||
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 ) ?
|
||||
( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart :
|
||||
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 */ );
|
||||
}
|
||||
|
||||
|
@ -40,12 +40,14 @@
|
||||
#define MAX_DAY 31
|
||||
#define MIN_DAY 1
|
||||
|
||||
uint16_t _FAT_filetime_getTimeFromRTC (void) {
|
||||
uint16_t _FAT_filetime_getTimeFromRTC ( void )
|
||||
{
|
||||
#ifdef USE_RTC_TIME
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1) {
|
||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
localtime_r( &epochTime, &timeParts );
|
||||
@ -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
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1) {
|
||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
localtime_r( &epochTime, &timeParts );
|
||||
@ -90,7 +94,8 @@ uint16_t _FAT_filetime_getDateFromRTC (void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d) {
|
||||
time_t _FAT_filetime_to_time_t ( uint16_t t, uint16_t d )
|
||||
{
|
||||
struct tm timeParts;
|
||||
|
||||
timeParts.tm_hour = t >> 11;
|
||||
|
@ -38,7 +38,8 @@
|
||||
#include "mem_allocate.h"
|
||||
#include "disc_fat.h"
|
||||
|
||||
static const devoptab_t dotab_fat = {
|
||||
static const devoptab_t dotab_fat =
|
||||
{
|
||||
"fat",
|
||||
sizeof ( FILE_STRUCT ),
|
||||
_FAT_open_r,
|
||||
@ -64,7 +65,8 @@ static const devoptab_t dotab_fat = {
|
||||
NULL /* Device data */
|
||||
};
|
||||
|
||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) {
|
||||
bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage )
|
||||
{
|
||||
PARTITION* partition;
|
||||
devoptab_t* devops;
|
||||
char* nameCopy;
|
||||
@ -72,13 +74,15 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
||||
if ( !interface->startup() )
|
||||
return false;
|
||||
|
||||
if(!interface->isInserted()) {
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
devops = _FAT_mem_allocate ( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
||||
if (!devops) {
|
||||
if ( !devops )
|
||||
{
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
@ -87,7 +91,8 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
||||
|
||||
// Initialize the file system
|
||||
partition = _FAT_partition_constructor ( interface, cacheSize, SectorsPerPage, startSector );
|
||||
if (!partition) {
|
||||
if ( !partition )
|
||||
{
|
||||
_FAT_mem_free ( devops );
|
||||
interface->shutdown();
|
||||
return false;
|
||||
@ -104,26 +109,31 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
||||
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 );
|
||||
}
|
||||
|
||||
void fatUnmount (const char* name) {
|
||||
void fatUnmount ( const char* name )
|
||||
{
|
||||
devoptab_t *devops;
|
||||
PARTITION* partition;
|
||||
const DISC_INTERFACE *disc;
|
||||
|
||||
devops = ( devoptab_t* )GetDeviceOpTab ( name );
|
||||
if (!devops) {
|
||||
if ( !devops )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
||||
if (devops->open_r != dotab_fat.open_r) {
|
||||
if ( devops->open_r != dotab_fat.open_r )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (RemoveDevice (name) == -1) {
|
||||
if ( RemoveDevice ( name ) == -1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@ -134,7 +144,8 @@ void fatUnmount (const char* name) {
|
||||
disc->shutdown();
|
||||
}
|
||||
|
||||
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
||||
bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
|
||||
{
|
||||
int i;
|
||||
int defaultDevice = -1;
|
||||
const DISC_INTERFACE *disc;
|
||||
@ -144,25 +155,30 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
||||
i++ )
|
||||
{
|
||||
disc = _FAT_disc_interfaces[i].getInterface();
|
||||
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) {
|
||||
if ( fatMount ( _FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE ) )
|
||||
{
|
||||
// The first device to successfully mount is set as the default
|
||||
if (defaultDevice < 0) {
|
||||
if ( defaultDevice < 0 )
|
||||
{
|
||||
defaultDevice = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultDevice < 0) {
|
||||
if ( defaultDevice < 0 )
|
||||
{
|
||||
// None of our devices mounted
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setAsDefaultDevice) {
|
||||
if ( setAsDefaultDevice )
|
||||
{
|
||||
char filePath[MAXPATHLEN * 2];
|
||||
strcpy ( filePath, _FAT_disc_interfaces[defaultDevice].name );
|
||||
strcat ( filePath, ":/" );
|
||||
#ifdef ARGV_MAGIC
|
||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL ) {
|
||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' ) != NULL )
|
||||
{
|
||||
// Check the app's path against each of our mounted devices, to see
|
||||
// if we can support it. If so, change to that path.
|
||||
for ( i = 0;
|
||||
@ -176,7 +192,8 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
||||
strcpy( filePath, __system_argv->argv[0] );
|
||||
lastSlash = strrchr( filePath, '/' );
|
||||
|
||||
if ( NULL != lastSlash) {
|
||||
if ( NULL != lastSlash )
|
||||
{
|
||||
if ( *( lastSlash - 1 ) == ':' ) lastSlash++;
|
||||
*lastSlash = 0;
|
||||
}
|
||||
@ -190,7 +207,8 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fatInitDefault (void) {
|
||||
bool fatInitDefault ( void )
|
||||
{
|
||||
return fatInit ( DEFAULT_CACHE_PAGES, true );
|
||||
}
|
||||
|
||||
|
@ -33,16 +33,19 @@
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static inline void* _FAT_mem_allocate (size_t size) {
|
||||
static inline void* _FAT_mem_allocate ( size_t size )
|
||||
{
|
||||
return malloc ( size );
|
||||
}
|
||||
|
||||
static inline void* _FAT_mem_align (size_t size) {
|
||||
static inline void* _FAT_mem_align ( size_t size )
|
||||
{
|
||||
|
||||
return memalign ( 32, size );
|
||||
}
|
||||
|
||||
static inline void _FAT_mem_free (void* mem) {
|
||||
static inline void _FAT_mem_free ( void* mem )
|
||||
{
|
||||
free ( mem );
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,8 @@ Data offsets
|
||||
*/
|
||||
|
||||
// BIOS Parameter Block offsets
|
||||
enum BPB {
|
||||
enum BPB
|
||||
{
|
||||
BPB_jmpBoot = 0x00,
|
||||
BPB_OEMName = 0x03,
|
||||
// BIOS Parameter Block
|
||||
@ -107,24 +108,28 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
|
||||
// Read first sector of disc
|
||||
if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) {
|
||||
if ( !_FAT_disc_readSectors ( disc, 0, 1, sectorBuffer ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy( part_table, sectorBuffer + 0x1BE, 16*4 );
|
||||
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 );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ( ptr[4] == 0 ) continue;
|
||||
|
||||
if(ptr[4]==0x0F) {
|
||||
if ( ptr[4] == 0x0F )
|
||||
{
|
||||
sec_t part_lba2 = part_lba;
|
||||
sec_t next_lba2 = 0;
|
||||
int n;
|
||||
@ -146,10 +151,13 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
|
||||
if ( next_lba2 == 0 ) break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !_FAT_disc_readSectors ( disc, part_lba, 1, sectorBuffer ) ) return 0;
|
||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
return part_lba;
|
||||
}
|
||||
}
|
||||
@ -157,31 +165,42 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) {
|
||||
PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector )
|
||||
{
|
||||
PARTITION* partition;
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
|
||||
// Read first sector of disc
|
||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
|
||||
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Make sure it is a valid MBR or boot sector
|
||||
if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) {
|
||||
if ( ( sectorBuffer[BPB_bootSig_55] != 0x55 ) || ( sectorBuffer[BPB_bootSig_AA] != 0xAA ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (startSector != 0) {
|
||||
if ( startSector != 0 )
|
||||
{
|
||||
// We're told where to start the partition, so just accept it
|
||||
} else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
||||
}
|
||||
else if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
// Check if there is a FAT string, which indicates this is a boot sector
|
||||
startSector = 0;
|
||||
} else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
||||
}
|
||||
else if ( !memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
// Check for FAT32
|
||||
startSector = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
startSector = FindFirstValidPartition( disc );
|
||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
|
||||
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -201,7 +220,8 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
||||
}
|
||||
|
||||
partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) );
|
||||
if (partition == NULL) {
|
||||
if ( partition == 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
|
||||
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->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall );
|
||||
if (partition->numberOfSectors == 0) {
|
||||
if ( partition->numberOfSectors == 0 )
|
||||
{
|
||||
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.firstFree = CLUSTER_FIRST;
|
||||
|
||||
if (clusterCount < CLUSTERS_PER_FAT12) {
|
||||
if ( clusterCount < CLUSTERS_PER_FAT12 )
|
||||
{
|
||||
partition->filesysType = FS_FAT12; // FAT12 volume
|
||||
} else if (clusterCount < CLUSTERS_PER_FAT16) {
|
||||
}
|
||||
else if ( clusterCount < CLUSTERS_PER_FAT16 )
|
||||
{
|
||||
partition->filesysType = FS_FAT16; // FAT16 volume
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
partition->filesysType = FS_FAT32; // FAT32 volume
|
||||
}
|
||||
|
||||
if (partition->filesysType != FS_FAT32) {
|
||||
if ( partition->filesysType != FS_FAT32 )
|
||||
{
|
||||
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set up for the FAT32 way
|
||||
partition->rootDirCluster = u8array_to_u32( sectorBuffer, BPB_FAT32_rootClus );
|
||||
// Check if FAT mirroring is enabled
|
||||
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) {
|
||||
if ( !( sectorBuffer[BPB_FAT32_extFlags] & 0x80 ) )
|
||||
{
|
||||
// Use the active FAT
|
||||
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * ( sectorBuffer[BPB_FAT32_extFlags] & 0x0F ) );
|
||||
}
|
||||
@ -276,14 +307,16 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
||||
return partition;
|
||||
}
|
||||
|
||||
void _FAT_partition_destructor (PARTITION* partition) {
|
||||
void _FAT_partition_destructor ( PARTITION* partition )
|
||||
{
|
||||
FILE_STRUCT* nextFile;
|
||||
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Synchronize open files
|
||||
nextFile = partition->firstOpenFile;
|
||||
while (nextFile) {
|
||||
while ( nextFile )
|
||||
{
|
||||
_FAT_syncToDisc ( nextFile );
|
||||
nextFile = nextFile->nextOpenFile;
|
||||
}
|
||||
@ -299,12 +332,14 @@ void _FAT_partition_destructor (PARTITION* partition) {
|
||||
_FAT_mem_free ( partition );
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_getPartitionFromPath (const char* path) {
|
||||
PARTITION* _FAT_partition_getPartitionFromPath ( const char* path )
|
||||
{
|
||||
const devoptab_t *devops;
|
||||
|
||||
devops = GetDeviceOpTab ( path );
|
||||
|
||||
if (!devops) {
|
||||
if ( !devops )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -40,14 +40,16 @@ extern const char* DEVICE_NAME;
|
||||
// Filesystem type
|
||||
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t fatStart;
|
||||
uint32_t sectorsPerFat;
|
||||
uint32_t lastCluster;
|
||||
uint32_t firstFree;
|
||||
} FAT;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
CACHE* cache;
|
||||
// Info about the partition
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -122,7 +122,8 @@ typedef char BIGSID[40];
|
||||
* (private to this module)
|
||||
*/
|
||||
|
||||
struct MAPLIST {
|
||||
struct MAPLIST
|
||||
{
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -49,7 +49,8 @@ extern ntfschar TXF_DATA[10];
|
||||
*
|
||||
* TODO: Describe them.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
@ -75,7 +76,8 @@ typedef enum {
|
||||
* any modification of the search context, to automagically get the next
|
||||
* matching attribute.
|
||||
*/
|
||||
struct _ntfs_attr_search_ctx {
|
||||
struct _ntfs_attr_search_ctx
|
||||
{
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
BOOL is_first;
|
||||
@ -174,7 +176,8 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
|
||||
* @state contains NTFS attribute specific flags describing this attribute
|
||||
* structure. See ntfs_attr_state_bits above.
|
||||
*/
|
||||
struct _ntfs_attr {
|
||||
struct _ntfs_attr
|
||||
{
|
||||
runlist_element *rl;
|
||||
ntfs_inode *ni;
|
||||
ATTR_TYPES type;
|
||||
@ -196,7 +199,8 @@ struct _ntfs_attr {
|
||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
||||
* structure
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
NA_NonResident, /* 1: Attribute is not resident. */
|
||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
@ -243,7 +247,8 @@ GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
||||
*
|
||||
* For convenience. Used in the attr structure.
|
||||
*/
|
||||
typedef union {
|
||||
typedef union
|
||||
{
|
||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||
a_val without specifying any of the below. */
|
||||
STANDARD_INFORMATION std_inf;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -62,7 +62,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -70,13 +71,15 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
|
||||
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
if ( !NInoAttrList( ni ) )
|
||||
{
|
||||
ntfs_log_trace( "Inode haven't got attribute list.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ni->attr_list) {
|
||||
if ( !ni->attr_list )
|
||||
{
|
||||
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -84,7 +87,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
|
||||
errno = 0;
|
||||
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
|
||||
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
||||
while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
|
||||
{
|
||||
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
|
||||
return 1;
|
||||
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
|
||||
@ -117,7 +121,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
( long long ) ni->mft_no,
|
||||
( unsigned ) le32_to_cpu( attr->type ) );
|
||||
|
||||
if (!ni || !attr) {
|
||||
if ( !ni || !attr )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -128,7 +133,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
if ( ni->nr_extents == -1 )
|
||||
ni = ni->base_ni;
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
if ( !NInoAttrList( ni ) )
|
||||
{
|
||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
@ -143,7 +149,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
|
||||
/* Find place for the new entry. */
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if (!ctx) {
|
||||
if ( !ctx )
|
||||
{
|
||||
err = errno;
|
||||
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 ) :
|
||||
0, ( attr->non_resident ) ? NULL : ( ( u8* )attr +
|
||||
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. */
|
||||
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) {
|
||||
if ( ctx->al_entry->lowest_vcn == attr->lowest_vcn )
|
||||
{
|
||||
err = EEXIST;
|
||||
ntfs_log_trace( "Such attribute already present in the "
|
||||
"attribute list.\n" );
|
||||
@ -165,9 +174,12 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
/* Add new entry after this extent. */
|
||||
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
|
||||
le16_to_cpu( ctx->al_entry->length ) );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for real errors. */
|
||||
if (errno != ENOENT) {
|
||||
if ( errno != ENOENT )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "Attribute lookup failed.\n" );
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
@ -201,12 +213,14 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
|
||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||
if (!na) {
|
||||
if ( !na )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
|
||||
if ( ntfs_attr_truncate( na, ni->attr_list_size + entry_len ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
||||
goto err_out;
|
||||
@ -250,7 +264,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
int err;
|
||||
|
||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
||||
if ( !ctx || !ctx->ntfs_ino || !ctx->al_entry )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -267,7 +282,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
( unsigned ) le32_to_cpu( ctx->al_entry->type ),
|
||||
( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) );
|
||||
|
||||
if (!NInoAttrList(base_ni)) {
|
||||
if ( !NInoAttrList( base_ni ) )
|
||||
{
|
||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
@ -281,12 +297,14 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
|
||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||
if (!na) {
|
||||
if ( !na )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, new_al_len)) {
|
||||
if ( ntfs_attr_truncate( na, new_al_len ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
||||
goto err_out;
|
||||
|
@ -34,20 +34,24 @@
|
||||
/*-----------------------------------------------------------------
|
||||
Functions to deal with little endian values stored in uint8_t arrays
|
||||
-----------------------------------------------------------------*/
|
||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
||||
static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
||||
}
|
||||
|
||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
||||
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
||||
}
|
||||
|
||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
||||
static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
}
|
||||
|
||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
||||
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
||||
|
@ -119,7 +119,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
u8 *buf, *lastbyte_buf;
|
||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
||||
|
||||
if (!na || start_bit < 0 || count < 0) {
|
||||
if ( !na || start_bit < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)",
|
||||
__FUNCTION__, na, ( long long )start_bit, ( long long )count );
|
||||
@ -145,16 +146,19 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
memset( buf, value ? 0xff : 0, bufsize );
|
||||
|
||||
/* If there is a first partial byte... */
|
||||
if (bit) {
|
||||
if ( bit )
|
||||
{
|
||||
/* read it in... */
|
||||
br = ntfs_attr_pread( na, start_bit >> 3, 1, buf );
|
||||
if (br != 1) {
|
||||
if ( br != 1 )
|
||||
{
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set or clear the appropriate bits in it. */
|
||||
while ((bit & 7) && count--) {
|
||||
while ( ( bit & 7 ) && count-- )
|
||||
{
|
||||
if ( value )
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
@ -168,11 +172,14 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
lastbyte = 0;
|
||||
lastbyte_buf = NULL;
|
||||
bit = count & 7;
|
||||
do {
|
||||
do
|
||||
{
|
||||
/* If there is a last partial byte... */
|
||||
if (count > 0 && bit) {
|
||||
if ( count > 0 && bit )
|
||||
{
|
||||
lastbyte_pos = ( ( count + 7 ) >> 3 ) + firstbyte;
|
||||
if (!lastbyte_pos) {
|
||||
if ( !lastbyte_pos )
|
||||
{
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error( "Lastbyte is zero. Leaving "
|
||||
"inconsistent metadata.\n" );
|
||||
@ -180,13 +187,15 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and it is in the currently loaded bitmap window... */
|
||||
if (lastbyte_pos <= bufsize) {
|
||||
if ( lastbyte_pos <= bufsize )
|
||||
{
|
||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||
|
||||
/* read the byte in... */
|
||||
br = ntfs_attr_pread( na, ( start_bit + count ) >>
|
||||
3, 1, lastbyte_buf );
|
||||
if (br != 1) {
|
||||
if ( br != 1 )
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
@ -196,7 +205,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set/clear the appropriate bits in it. */
|
||||
while (bit && count--) {
|
||||
while ( bit && count-- )
|
||||
{
|
||||
if ( value )
|
||||
*lastbyte_buf |= 1 << --bit;
|
||||
else
|
||||
@ -212,7 +222,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
/* Write the prepared buffer to disk. */
|
||||
tmp = ( start_bit >> 3 ) - firstbyte;
|
||||
br = ntfs_attr_pwrite( na, tmp, bufsize, buf );
|
||||
if (br != bufsize) {
|
||||
if ( br != bufsize )
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
@ -224,7 +235,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
|
||||
/* Update counters. */
|
||||
tmp = ( bufsize - firstbyte - lastbyte ) << 3;
|
||||
if (firstbyte) {
|
||||
if ( firstbyte )
|
||||
{
|
||||
firstbyte = 0;
|
||||
/*
|
||||
* Re-set the partial first byte so a subsequent write
|
||||
@ -237,7 +249,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) )
|
||||
bufsize = tmp;
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
if ( lastbyte && count != 0 )
|
||||
{
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error( "Last buffer but count is not zero "
|
||||
"(%lld). Leaving inconsistent metadata.\n",
|
||||
@ -245,7 +258,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
}
|
||||
while ( count > 0 );
|
||||
|
||||
ret = 0;
|
||||
|
||||
|
@ -65,21 +65,24 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
ntfs_log_debug( "Beginning bootsector check.\n" );
|
||||
|
||||
ntfs_log_debug( "Checking OEMid, NTFS signature.\n" );
|
||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
||||
if ( b->oem_id != cpu_to_le64( 0x202020205346544eULL ) ) /* "NTFS " */
|
||||
{
|
||||
ntfs_log_error( "NTFS signature is missing.\n" );
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Checking bytes per sector.\n" );
|
||||
if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 ||
|
||||
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
|
||||
le16_to_cpu( b->bpb.bytes_per_sector ) > 4096 )
|
||||
{
|
||||
ntfs_log_error( "Unexpected bytes per sector value (%d).\n",
|
||||
le16_to_cpu( b->bpb.bytes_per_sector ) );
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Checking sectors per cluster.\n" );
|
||||
switch (b->bpb.sectors_per_cluster) {
|
||||
switch ( b->bpb.sectors_per_cluster )
|
||||
{
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||
break;
|
||||
default:
|
||||
@ -91,7 +94,8 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
ntfs_log_debug( "Checking cluster size.\n" );
|
||||
i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) *
|
||||
b->bpb.sectors_per_cluster;
|
||||
if (i > 65536) {
|
||||
if ( i > 65536 )
|
||||
{
|
||||
ntfs_log_error( "Unexpected cluster size (%d).\n", i );
|
||||
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_per_fat ) ||
|
||||
le32_to_cpu( b->bpb.large_sectors ) ||
|
||||
b->bpb.fats) {
|
||||
b->bpb.fats )
|
||||
{
|
||||
ntfs_log_error( "Reserved fields aren't zero "
|
||||
"(%d, %d, %d, %d, %d, %d).\n",
|
||||
le16_to_cpu( b->bpb.reserved_sectors ),
|
||||
@ -116,8 +121,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
|
||||
ntfs_log_debug( "Checking clusters per mft record.\n" );
|
||||
if ( ( u8 )b->clusters_per_mft_record < 0xe1 ||
|
||||
(u8)b->clusters_per_mft_record > 0xf7) {
|
||||
switch (b->clusters_per_mft_record) {
|
||||
( u8 )b->clusters_per_mft_record > 0xf7 )
|
||||
{
|
||||
switch ( b->clusters_per_mft_record )
|
||||
{
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
@ -129,8 +136,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
|
||||
ntfs_log_debug( "Checking clusters per index block.\n" );
|
||||
if ( ( u8 )b->clusters_per_index_record < 0xe1 ||
|
||||
(u8)b->clusters_per_index_record > 0xf7) {
|
||||
switch (b->clusters_per_index_record) {
|
||||
( u8 )b->clusters_per_index_record > 0xf7 )
|
||||
{
|
||||
switch ( b->clusters_per_index_record )
|
||||
{
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
@ -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;
|
||||
ntfs_log_debug( "SectorsPerCluster = 0x%x\n", sectors_per_cluster );
|
||||
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
|
||||
if ( sectors_per_cluster & ( sectors_per_cluster - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2."
|
||||
"\n", sectors_per_cluster );
|
||||
return -1;
|
||||
@ -196,13 +206,15 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
|
||||
sectors = sle64_to_cpu( bs->number_of_sectors );
|
||||
ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors );
|
||||
if (!sectors) {
|
||||
if ( !sectors )
|
||||
{
|
||||
ntfs_log_error( "Volume size is set to zero.\n" );
|
||||
return -1;
|
||||
}
|
||||
if ( vol->dev->d_ops->seek( vol->dev,
|
||||
( sectors - 1 ) << vol->sector_size_bits,
|
||||
SEEK_SET) == -1) {
|
||||
SEEK_SET ) == -1 )
|
||||
{
|
||||
ntfs_log_perror( "Failed to read last sector (%lld)",
|
||||
( long long )sectors );
|
||||
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( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn );
|
||||
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 "
|
||||
"greater than the number of clusters (%lld).\n",
|
||||
( 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;
|
||||
if (vol->cluster_size & (vol->cluster_size - 1)) {
|
||||
if ( vol->cluster_size & ( vol->cluster_size - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "cluster_size (%d) is not a power of 2.\n",
|
||||
vol->cluster_size );
|
||||
return -1;
|
||||
@ -250,7 +264,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
vol->mft_record_size = 1 << -c;
|
||||
else
|
||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
||||
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
|
||||
if ( vol->mft_record_size & ( vol->mft_record_size - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "mft_record_size (%d) is not a power of 2.\n",
|
||||
vol->mft_record_size );
|
||||
return -1;
|
||||
|
@ -67,12 +67,15 @@ static void inserthashindex(struct CACHE_HEADER *cache,
|
||||
struct HASH_ENTRY *link;
|
||||
struct HASH_ENTRY *first;
|
||||
|
||||
if (cache->dohash) {
|
||||
if ( cache->dohash )
|
||||
{
|
||||
h = cache->dohash( current );
|
||||
if ((h >= 0) && (h < cache->max_hash)) {
|
||||
if ( ( h >= 0 ) && ( h < cache->max_hash ) )
|
||||
{
|
||||
/* get a free link and insert at top of hash list */
|
||||
link = cache->free_hash;
|
||||
if (link) {
|
||||
if ( link )
|
||||
{
|
||||
cache->free_hash = link->next;
|
||||
first = cache->first_hash[h];
|
||||
if ( first )
|
||||
@ -81,13 +84,17 @@ static void inserthashindex(struct CACHE_HEADER *cache,
|
||||
link->next = NULL;
|
||||
link->entry = current;
|
||||
cache->first_hash[h] = link;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "No more hash entries,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name );
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Illegal hash value,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name );
|
||||
@ -106,29 +113,37 @@ static void drophashindex(struct CACHE_HEADER *cache,
|
||||
struct HASH_ENTRY *link;
|
||||
struct HASH_ENTRY *previous;
|
||||
|
||||
if (cache->dohash) {
|
||||
if ((hash >= 0) && (hash < cache->max_hash)) {
|
||||
if ( cache->dohash )
|
||||
{
|
||||
if ( ( hash >= 0 ) && ( hash < cache->max_hash ) )
|
||||
{
|
||||
/* find the link and unlink */
|
||||
link = cache->first_hash[hash];
|
||||
previous = ( struct HASH_ENTRY* )NULL;
|
||||
while (link && (link->entry != current)) {
|
||||
while ( link && ( link->entry != current ) )
|
||||
{
|
||||
previous = link;
|
||||
link = link->next;
|
||||
}
|
||||
if (link) {
|
||||
if ( link )
|
||||
{
|
||||
if ( previous )
|
||||
previous->next = link->next;
|
||||
else
|
||||
cache->first_hash[hash] = link->next;
|
||||
link->next = cache->free_hash;
|
||||
cache->free_hash = link;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Bad hash list,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name );
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Illegal hash value,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name );
|
||||
@ -153,8 +168,10 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
int h;
|
||||
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
if (cache) {
|
||||
if (cache->dohash) {
|
||||
if ( cache )
|
||||
{
|
||||
if ( cache->dohash )
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* locate the entry if present
|
||||
@ -166,21 +183,25 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
if ( link )
|
||||
current = link->entry;
|
||||
}
|
||||
if (!cache->dohash) {
|
||||
if ( !cache->dohash )
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list if no hash table
|
||||
* or if hashing has just failed
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
while ( current
|
||||
&& compare(current, wanted)) {
|
||||
&& compare( current, wanted ) )
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
if (current) {
|
||||
if ( current )
|
||||
{
|
||||
previous = current->previous;
|
||||
cache->hits++;
|
||||
if (previous) {
|
||||
if ( previous )
|
||||
{
|
||||
/*
|
||||
* found and not at head of list, unlink from current
|
||||
* position and relink as head of list
|
||||
@ -219,8 +240,10 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
int h;
|
||||
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
if (cache) {
|
||||
if (cache->dohash) {
|
||||
if ( cache )
|
||||
{
|
||||
if ( cache->dohash )
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* find out whether the entry if present
|
||||
@ -229,11 +252,13 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
link = cache->first_hash[h];
|
||||
while ( link && compare( link->entry, item ) )
|
||||
link = link->next;
|
||||
if (link) {
|
||||
if ( link )
|
||||
{
|
||||
current = link->entry;
|
||||
}
|
||||
}
|
||||
if (!cache->dohash) {
|
||||
if ( !cache->dohash )
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list to locate the end,
|
||||
* and find out whether the entry is already in list
|
||||
@ -242,12 +267,14 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
while ( current
|
||||
&& compare(current, item)) {
|
||||
&& compare( current, item ) )
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!current) {
|
||||
if ( !current )
|
||||
{
|
||||
/*
|
||||
* Not in list, get a free entry or reuse the
|
||||
* last entry, and relink as head of list
|
||||
@ -256,18 +283,23 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
* an entry is reused.
|
||||
*/
|
||||
|
||||
if (cache->free_entry) {
|
||||
if ( cache->free_entry )
|
||||
{
|
||||
current = cache->free_entry;
|
||||
cache->free_entry = cache->free_entry->next;
|
||||
if (item->varsize) {
|
||||
if ( item->varsize )
|
||||
{
|
||||
current->variable = ntfs_malloc(
|
||||
item->varsize );
|
||||
} else
|
||||
}
|
||||
else
|
||||
current->variable = ( void* )NULL;
|
||||
current->varsize = item->varsize;
|
||||
if ( !cache->oldest_entry )
|
||||
cache->oldest_entry = current;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reusing the oldest entry */
|
||||
current = cache->oldest_entry;
|
||||
before = current->previous;
|
||||
@ -278,7 +310,8 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
if ( cache->dofree )
|
||||
cache->dofree( current );
|
||||
cache->oldest_entry = current->previous;
|
||||
if (item->varsize) {
|
||||
if ( item->varsize )
|
||||
{
|
||||
if ( current->varsize )
|
||||
current->variable = realloc(
|
||||
current->variable,
|
||||
@ -286,7 +319,9 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
else
|
||||
current->variable = ntfs_malloc(
|
||||
item->varsize );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( current->varsize )
|
||||
free( current->variable );
|
||||
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 = current;
|
||||
memcpy( current->fixed, item->fixed, cache->fixed_size );
|
||||
if (item->varsize) {
|
||||
if (current->variable) {
|
||||
if ( item->varsize )
|
||||
{
|
||||
if ( current->variable )
|
||||
{
|
||||
memcpy( current->variable,
|
||||
item->variable, item->varsize );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* no more memory for variable part
|
||||
* recycle entry in free list
|
||||
@ -314,7 +353,9 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
cache->free_entry = current;
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
current->variable = ( void* )NULL;
|
||||
current->varsize = 0;
|
||||
}
|
||||
@ -384,21 +425,26 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
count = 0;
|
||||
if (cache) {
|
||||
if (!(flags & CACHE_NOHASH) && cache->dohash) {
|
||||
if ( cache )
|
||||
{
|
||||
if ( !( flags & CACHE_NOHASH ) && cache->dohash )
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* find out whether the entry if present
|
||||
*/
|
||||
h = cache->dohash( item );
|
||||
link = cache->first_hash[h];
|
||||
while (link) {
|
||||
while ( link )
|
||||
{
|
||||
if ( compare( link->entry, item ) )
|
||||
link = link->next;
|
||||
else {
|
||||
else
|
||||
{
|
||||
current = link->entry;
|
||||
link = link->next;
|
||||
if (current) {
|
||||
if ( current )
|
||||
{
|
||||
drophashindex( cache, current, h );
|
||||
do_invalidate( cache,
|
||||
current, flags );
|
||||
@ -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
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
previous = ( struct CACHED_GENERIC* )NULL;
|
||||
while (current) {
|
||||
if (!compare(current, item)) {
|
||||
while ( current )
|
||||
{
|
||||
if ( !compare( current, item ) )
|
||||
{
|
||||
next = current->next;
|
||||
if ( cache->dohash )
|
||||
drophashindex( cache, current,
|
||||
@ -422,7 +471,9 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
do_invalidate( cache, current, flags );
|
||||
current = next;
|
||||
count++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = current;
|
||||
current = current->next;
|
||||
}
|
||||
@ -438,7 +489,8 @@ int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
if (cache) {
|
||||
if ( cache )
|
||||
{
|
||||
if ( cache->dohash )
|
||||
drophashindex( cache, item, cache->dohash( item ) );
|
||||
do_invalidate( cache, item, flags );
|
||||
@ -455,8 +507,10 @@ static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
||||
{
|
||||
struct CACHED_GENERIC *entry;
|
||||
|
||||
if (cache) {
|
||||
for (entry=cache->most_recent_entry; entry; entry=entry->next) {
|
||||
if ( cache )
|
||||
{
|
||||
for ( entry = cache->most_recent_entry; entry; entry = entry->next )
|
||||
{
|
||||
if ( cache->dofree )
|
||||
cache->dofree( entry );
|
||||
if ( entry->variable )
|
||||
@ -491,14 +545,18 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
size += item_count*sizeof( struct HASH_ENTRY )
|
||||
+ max_hash*sizeof( struct HASH_ENTRY* );
|
||||
cache = ( struct CACHE_HEADER* )ntfs_malloc( size );
|
||||
if (cache) {
|
||||
if ( cache )
|
||||
{
|
||||
/* header */
|
||||
cache->name = name;
|
||||
cache->dofree = dofree;
|
||||
if (dohash && max_hash) {
|
||||
if ( dohash && max_hash )
|
||||
{
|
||||
cache->dohash = dohash;
|
||||
cache->max_hash = max_hash;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
cache->max_hash = 0;
|
||||
}
|
||||
@ -511,7 +569,8 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
cache->oldest_entry = ( struct CACHED_GENERIC* )NULL;
|
||||
cache->free_entry = &cache->entry[0];
|
||||
pc = &cache->entry[0];
|
||||
for (i=0; i<(item_count - 1); i++) {
|
||||
for ( i = 0; i < ( item_count - 1 ); i++ )
|
||||
{
|
||||
qc = ( struct CACHED_GENERIC* )( ( char* )pc
|
||||
+ full_item_size );
|
||||
pc->next = qc;
|
||||
@ -524,17 +583,20 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
pc->variable = ( void* )NULL;
|
||||
pc->varsize = 0;
|
||||
|
||||
if (max_hash) {
|
||||
if ( max_hash )
|
||||
{
|
||||
/* chain the hash entries */
|
||||
ph = ( struct HASH_ENTRY* )( ( ( char* )pc ) + full_item_size );
|
||||
cache->free_hash = ph;
|
||||
for (i=0; i<(item_count - 1); i++) {
|
||||
for ( i = 0; i < ( item_count - 1 ); i++ )
|
||||
{
|
||||
qh = &ph[1];
|
||||
ph->next = qh;
|
||||
ph = qh;
|
||||
}
|
||||
/* special for the last entry */
|
||||
if (item_count) {
|
||||
if ( item_count )
|
||||
{
|
||||
ph->next = ( struct HASH_ENTRY* )NULL;
|
||||
}
|
||||
/* create and initialize the hash indexes */
|
||||
@ -542,7 +604,9 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
cache->first_hash = px;
|
||||
for ( i = 0; i < max_hash; i++ )
|
||||
px[i] = ( struct HASH_ENTRY* )NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->free_hash = ( struct HASH_ENTRY* )NULL;
|
||||
cache->first_hash = ( struct HASH_ENTRY** )NULL;
|
||||
}
|
||||
|
@ -24,19 +24,22 @@
|
||||
|
||||
#include "volume.h"
|
||||
|
||||
struct CACHED_GENERIC {
|
||||
struct CACHED_GENERIC
|
||||
{
|
||||
struct CACHED_GENERIC *next;
|
||||
struct CACHED_GENERIC *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
union {
|
||||
union
|
||||
{
|
||||
/* force alignment for pointers and u64 */
|
||||
u64 u64align;
|
||||
void *ptralign;
|
||||
} fixed[0];
|
||||
} ;
|
||||
|
||||
struct CACHED_INODE {
|
||||
struct CACHED_INODE
|
||||
{
|
||||
struct CACHED_INODE *next;
|
||||
struct CACHED_INODE *previous;
|
||||
const char *pathname;
|
||||
@ -45,7 +48,8 @@ struct CACHED_INODE {
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
struct CACHED_NIDATA {
|
||||
struct CACHED_NIDATA
|
||||
{
|
||||
struct CACHED_NIDATA *next;
|
||||
struct CACHED_NIDATA *previous;
|
||||
const char *pathname; /* not used */
|
||||
@ -55,7 +59,8 @@ struct CACHED_NIDATA {
|
||||
ntfs_inode *ni;
|
||||
} ;
|
||||
|
||||
struct CACHED_LOOKUP {
|
||||
struct CACHED_LOOKUP
|
||||
{
|
||||
struct CACHED_LOOKUP *next;
|
||||
struct CACHED_LOOKUP *previous;
|
||||
const char *name;
|
||||
@ -65,7 +70,8 @@ struct CACHED_LOOKUP {
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
CACHE_FREE = 1,
|
||||
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 int ( *cache_hash )( const struct CACHED_GENERIC *cached );
|
||||
|
||||
struct HASH_ENTRY {
|
||||
struct HASH_ENTRY
|
||||
{
|
||||
struct HASH_ENTRY *next;
|
||||
struct CACHED_GENERIC *entry;
|
||||
} ;
|
||||
|
||||
struct CACHE_HEADER {
|
||||
struct CACHE_HEADER
|
||||
{
|
||||
const char *name;
|
||||
struct CACHED_GENERIC *most_recent_entry;
|
||||
struct CACHED_GENERIC *oldest_entry;
|
||||
|
@ -45,23 +45,27 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize) {
|
||||
NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize )
|
||||
{
|
||||
NTFS_CACHE* cache;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL;
|
||||
|
||||
if (numberOfPages < 4) {
|
||||
if ( numberOfPages < 4 )
|
||||
{
|
||||
numberOfPages = 4;
|
||||
}
|
||||
|
||||
if (sectorsPerPage < 32) {
|
||||
if ( sectorsPerPage < 32 )
|
||||
{
|
||||
sectorsPerPage = 32;
|
||||
}
|
||||
|
||||
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
|
||||
if (cache == NULL) {
|
||||
if ( cache == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -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 );
|
||||
if (cacheEntries == NULL) {
|
||||
if ( cacheEntries == NULL )
|
||||
{
|
||||
ntfs_free ( cache );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numberOfPages; i++) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
@ -91,7 +97,8 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
void _NTFS_cache_destructor ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if ( cache == NULL ) return;
|
||||
@ -100,7 +107,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
_NTFS_cache_flush( cache );
|
||||
|
||||
// Free memory in reverse allocation order
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
ntfs_free ( cache->cacheEntries[i].cache );
|
||||
}
|
||||
ntfs_free ( cache->cacheEntries );
|
||||
@ -109,7 +117,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
static u32 accessTime()
|
||||
{
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
@ -125,20 +134,24 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
||||
{
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &( cacheEntries[i] );
|
||||
}
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
||||
{
|
||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
||||
{
|
||||
if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
@ -155,7 +168,8 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
return &( cacheEntries[oldUsed] );
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage( NTFS_CACHE *cache, sec_t sector, sec_t count )
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
@ -163,16 +177,22 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||
{
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
if ( sector > cacheEntries[i].sector )
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
@ -189,7 +209,8 @@ bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,voi
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
|
||||
while(numSectors>0) {
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
@ -227,11 +248,13 @@ bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t secto
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
bool _NTFS_cache_readLittleEndianValue ( NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||
|
||||
switch(num_bytes) {
|
||||
switch ( num_bytes )
|
||||
{
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
@ -261,10 +284,12 @@ bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
bool _NTFS_cache_writeLittleEndianValue ( NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
||||
{
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
|
||||
switch(size) {
|
||||
switch ( size )
|
||||
{
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||
@ -307,9 +332,11 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
{
|
||||
entry = _NTFS_cache_findPage( cache, sector, numSectors );
|
||||
|
||||
if(entry!=NULL) {
|
||||
if ( entry != NULL )
|
||||
{
|
||||
|
||||
if ( entry->sector > sector) {
|
||||
if ( entry->sector > sector )
|
||||
{
|
||||
|
||||
secs_to_write = entry->sector - sector;
|
||||
|
||||
@ -332,7 +359,9 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->disc->writeSectors( sector, numSectors, src );
|
||||
numSectors = 0;
|
||||
}
|
||||
@ -343,13 +372,17 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
bool _NTFS_cache_flush ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if ( cache == NULL ) return true;
|
||||
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
if (cache->cacheEntries[i].dirty) {
|
||||
if (!cache->disc->writeSectors (cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
if ( cache->cacheEntries[i].dirty )
|
||||
{
|
||||
if ( !cache->disc->writeSectors ( cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -359,13 +392,15 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
||||
void _NTFS_cache_invalidate ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if ( cache == NULL )
|
||||
return;
|
||||
|
||||
_NTFS_cache_flush( cache );
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
|
@ -46,7 +46,8 @@
|
||||
#include <ogc/disc_io.h>
|
||||
#include <gccore.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
u64 last_access;
|
||||
@ -54,7 +55,8 @@ typedef struct {
|
||||
u8* cache;
|
||||
} NTFS_CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
|
@ -60,7 +60,8 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
rc = memcmp( data1, data2, min( data1_len, data2_len ) );
|
||||
if (!rc && (data1_len != data2_len)) {
|
||||
if ( !rc && ( data1_len != data2_len ) )
|
||||
{
|
||||
if ( data1_len < data2_len )
|
||||
rc = -1;
|
||||
else
|
||||
@ -90,7 +91,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
u32 d1, d2;
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if (data1_len != data2_len || data1_len != 4) {
|
||||
if ( data1_len != data2_len || data1_len != 4 )
|
||||
{
|
||||
ntfs_log_error( "data1_len or/and data2_len not equal to 4.\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
@ -98,7 +100,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
d2 = le32_to_cpup( data2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if ( d1 == d2 )
|
||||
rc = 0;
|
||||
else
|
||||
@ -124,22 +127,26 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
||||
u32 d1, d2;
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) {
|
||||
if ( ( data1_len != data2_len ) || ( data1_len <= 0 ) || ( data1_len & 3 ) )
|
||||
{
|
||||
ntfs_log_error( "data1_len or data2_len not valid\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = ( const le32* )data1;
|
||||
p2 = ( const le32* )data2;
|
||||
len = data1_len;
|
||||
do {
|
||||
do
|
||||
{
|
||||
d1 = le32_to_cpup( p1 );
|
||||
p1++;
|
||||
d2 = le32_to_cpup( p2 );
|
||||
p2++;
|
||||
} while ((d1 == d2) && ((len -= 4) > 0));
|
||||
}
|
||||
while ( ( d1 == d2 ) && ( ( len -= 4 ) > 0 ) );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if ( d1 == d2 )
|
||||
rc = 0;
|
||||
else
|
||||
@ -171,7 +178,8 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
||||
const le32 *p1, *p2;
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if (data1_len != data2_len || data1_len != 8) {
|
||||
if ( data1_len != data2_len || data1_len != 8 )
|
||||
{
|
||||
ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
@ -181,17 +189,20 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
||||
d2 = le32_to_cpup( p2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
p1++;
|
||||
p2++;
|
||||
d1 = le32_to_cpup( p1 );
|
||||
d2 = le32_to_cpup( p2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else
|
||||
@ -246,7 +257,8 @@ COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
|
||||
{
|
||||
COLLATE collate;
|
||||
|
||||
switch (cr) {
|
||||
switch ( cr )
|
||||
{
|
||||
case COLLATION_BINARY :
|
||||
collate = ntfs_collate_binary;
|
||||
break;
|
||||
|
@ -41,23 +41,28 @@ int ffs(int x)
|
||||
|
||||
if ( !x )
|
||||
return 0;
|
||||
if (!(x & 0xffff)) {
|
||||
if ( !( x & 0xffff ) )
|
||||
{
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (!(x & 0xff)) {
|
||||
if ( !( x & 0xff ) )
|
||||
{
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (!(x & 0xf)) {
|
||||
if ( !( x & 0xf ) )
|
||||
{
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (!(x & 3)) {
|
||||
if ( !( x & 3 ) )
|
||||
{
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
if ( !( x & 1 ) )
|
||||
{
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
@ -120,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>
|
||||
#endif
|
||||
|
||||
int daemon(int nochdir, int noclose) {
|
||||
int daemon( int nochdir, int noclose )
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (fork()) {
|
||||
switch ( fork() )
|
||||
{
|
||||
case -1:
|
||||
return ( -1 );
|
||||
case 0:
|
||||
@ -138,7 +145,8 @@ int daemon(int nochdir, int noclose) {
|
||||
if ( !nochdir )
|
||||
( void )chdir( "/" );
|
||||
|
||||
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
if ( !noclose && ( fd = open( "/dev/null", O_RDWR, 0 ) ) != -1 )
|
||||
{
|
||||
( void )dup2( fd, 0 );
|
||||
( void )dup2( fd, 1 );
|
||||
( void )dup2( fd, 2 );
|
||||
@ -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.
|
||||
*/
|
||||
char *strsep(char **stringp, const char *delim) {
|
||||
char *strsep( char **stringp, const char *delim )
|
||||
{
|
||||
char *s;
|
||||
const char *spanp;
|
||||
int c, sc;
|
||||
@ -226,11 +235,14 @@ char *strsep(char **stringp, const char *delim) {
|
||||
|
||||
if ( ( s = *stringp ) == NULL )
|
||||
return ( NULL );
|
||||
for (tok = s;;) {
|
||||
for ( tok = s;; )
|
||||
{
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
do
|
||||
{
|
||||
if ( ( sc = *spanp++ ) == c )
|
||||
{
|
||||
if ( c == 0 )
|
||||
s = NULL;
|
||||
else
|
||||
@ -238,7 +250,8 @@ char *strsep(char **stringp, const char *delim) {
|
||||
*stringp = s;
|
||||
return ( tok );
|
||||
}
|
||||
} while (sc != 0);
|
||||
}
|
||||
while ( sc != 0 );
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,18 +47,22 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||
int i = 0;
|
||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||
"LCN_unknown " };
|
||||
"LCN_unknown "
|
||||
};
|
||||
|
||||
ntfs_log_debug( "NTFS-fs DEBUG: Dumping runlist (values in hex):\n" );
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
ntfs_log_debug( "Run list not present.\n" );
|
||||
return;
|
||||
}
|
||||
ntfs_log_debug( "VCN LCN Run length\n" );
|
||||
do {
|
||||
do
|
||||
{
|
||||
LCN lcn = ( rl + i )->lcn;
|
||||
|
||||
if (lcn < (LCN)0) {
|
||||
if ( lcn < ( LCN )0 )
|
||||
{
|
||||
int idx = -lcn - 1;
|
||||
|
||||
if ( idx > -LCN_EINVAL - 1 )
|
||||
@ -67,12 +71,14 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||
( long long )rl[i].vcn, lcn_str[idx],
|
||||
( long long )rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)" );
|
||||
} else
|
||||
}
|
||||
else
|
||||
ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n",
|
||||
( long long )rl[i].vcn, ( long long )rl[i].lcn,
|
||||
( long long )rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)" );
|
||||
} while (rl[i++].length);
|
||||
}
|
||||
while ( rl[i++].length );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -108,14 +108,17 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
{
|
||||
struct ntfs_device *dev;
|
||||
|
||||
if (!name) {
|
||||
if ( !name )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = ntfs_malloc( sizeof( struct ntfs_device ) );
|
||||
if (dev) {
|
||||
if (!(dev->d_name = strdup(name))) {
|
||||
if ( dev )
|
||||
{
|
||||
if ( !( dev->d_name = strdup( name ) ) )
|
||||
{
|
||||
int eo = errno;
|
||||
free( dev );
|
||||
errno = eo;
|
||||
@ -141,11 +144,13 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
*/
|
||||
int ntfs_device_free( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (NDevOpen(dev)) {
|
||||
if ( NDevOpen( dev ) )
|
||||
{
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
@ -180,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 );
|
||||
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
if ( !b || count < 0 || pos < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -189,7 +195,8 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
||||
|
||||
dops = dev->d_ops;
|
||||
|
||||
for (total = 0; count; count -= br, total += br) {
|
||||
for ( total = 0; count; count -= br, total += br )
|
||||
{
|
||||
br = dops->pread( dev, ( char* )b + total, count, pos + total );
|
||||
/* If everything ok, continue. */
|
||||
if ( br > 0 )
|
||||
@ -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 );
|
||||
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
if ( !b || count < 0 || pos < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if ( !count )
|
||||
return 0;
|
||||
if (NDevReadOnly(dev)) {
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
errno = EROFS;
|
||||
goto out;
|
||||
}
|
||||
@ -245,7 +254,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
dops = dev->d_ops;
|
||||
|
||||
NDevSetDirty( dev );
|
||||
for (total = 0; count; count -= written, total += written) {
|
||||
for ( total = 0; count; count -= written, total += written )
|
||||
{
|
||||
written = dops->pwrite( dev, ( const char* )b + total, count,
|
||||
pos + total );
|
||||
/* If everything ok, continue. */
|
||||
@ -299,7 +309,8 @@ s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
{
|
||||
s64 br, i;
|
||||
|
||||
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
|
||||
if ( bksize & ( bksize - 1 ) || bksize % NTFS_BLOCK_SIZE )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -356,19 +367,22 @@ s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
{
|
||||
s64 written, i;
|
||||
|
||||
if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
|
||||
if ( count < 0 || bksize % NTFS_BLOCK_SIZE )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ( !count )
|
||||
return 0;
|
||||
/* Prepare data for writing. */
|
||||
for (i = 0; i < count; ++i) {
|
||||
for ( i = 0; i < count; ++i )
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ntfs_mst_pre_write_fixup( ( NTFS_RECORD* )
|
||||
( ( u8* )b + i * bksize ), bksize );
|
||||
if (err < 0) {
|
||||
if ( err < 0 )
|
||||
{
|
||||
/* Abort write at this position. */
|
||||
if ( !i )
|
||||
return err;
|
||||
@ -403,11 +417,13 @@ s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
||||
{
|
||||
s64 br;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
if ( !vol || lcn < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
if ( vol->nr_clusters < lcn + count )
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror( "Trying to read outside of volume "
|
||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
||||
@ -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,
|
||||
count << vol->cluster_size_bits, b );
|
||||
if (br < 0) {
|
||||
if ( br < 0 )
|
||||
{
|
||||
ntfs_log_perror( "Error reading cluster(s)" );
|
||||
return br;
|
||||
}
|
||||
@ -439,11 +456,13 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
{
|
||||
s64 bw;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
if ( !vol || lcn < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
if ( vol->nr_clusters < lcn + count )
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror( "Trying to write outside of volume "
|
||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
||||
@ -455,7 +474,8 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
count << vol->cluster_size_bits, b );
|
||||
else
|
||||
bw = count << vol->cluster_size_bits;
|
||||
if (bw < 0) {
|
||||
if ( bw < 0 )
|
||||
{
|
||||
ntfs_log_perror( "Error writing cluster(s)" );
|
||||
return bw;
|
||||
}
|
||||
@ -498,14 +518,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
{
|
||||
s64 high, low;
|
||||
|
||||
if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
|
||||
if ( !dev || block_size <= 0 || ( block_size - 1 ) & block_size )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKGETSIZE64
|
||||
{ u64 size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
|
||||
if ( dev->d_ops->ioctl( dev, BLKGETSIZE64, &size ) >= 0 )
|
||||
{
|
||||
ntfs_log_debug( "BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||
( unsigned long long )size,
|
||||
( unsigned long long )size );
|
||||
@ -516,7 +538,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
#ifdef BLKGETSIZE
|
||||
{ unsigned long size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
|
||||
if ( dev->d_ops->ioctl( dev, BLKGETSIZE, &size ) >= 0 )
|
||||
{
|
||||
ntfs_log_debug( "BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
size, size );
|
||||
return ( s64 )size * 512 / block_size;
|
||||
@ -526,7 +549,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
#ifdef FDGETPRM
|
||||
{ struct floppy_struct this_floppy;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
|
||||
if ( dev->d_ops->ioctl( dev, FDGETPRM, &this_floppy ) >= 0 )
|
||||
{
|
||||
ntfs_log_debug( "FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
( unsigned long )this_floppy.size,
|
||||
( unsigned long )this_floppy.size );
|
||||
@ -541,7 +565,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
low = 0LL;
|
||||
for ( high = 1024LL; !ntfs_device_offset_valid( dev, high ); high <<= 1 )
|
||||
low = high;
|
||||
while (low < high - 1LL) {
|
||||
while ( low < high - 1LL )
|
||||
{
|
||||
const s64 mid = ( low + high ) / 2;
|
||||
|
||||
if ( !ntfs_device_offset_valid( dev, mid ) )
|
||||
@ -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 )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ struct hd_geometry geo;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||
{
|
||||
ntfs_log_debug( "HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
||||
geo.start, geo.start );
|
||||
return geo.start;
|
||||
@ -600,14 +627,16 @@ s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
|
||||
*/
|
||||
int ntfs_device_heads_get( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ struct hd_geometry geo;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||
{
|
||||
ntfs_log_debug( "HDIO_GETGEO heads = %u (0x%x)\n",
|
||||
( unsigned )geo.heads,
|
||||
( unsigned )geo.heads );
|
||||
@ -634,14 +663,16 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
|
||||
*/
|
||||
int ntfs_device_sectors_per_track_get( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ struct hd_geometry geo;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||
{
|
||||
ntfs_log_debug( "HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
||||
( unsigned )geo.sectors,
|
||||
( unsigned )geo.sectors );
|
||||
@ -668,7 +699,8 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
|
||||
*/
|
||||
int ntfs_device_sector_size_get( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -676,7 +708,8 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
||||
{
|
||||
int sect_size = 0;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) {
|
||||
if ( !dev->d_ops->ioctl( dev, BLKSSZGET, §_size ) )
|
||||
{
|
||||
ntfs_log_debug( "BLKSSZGET sector size = %d bytes\n",
|
||||
sect_size );
|
||||
return sect_size;
|
||||
@ -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 block_size __attribute__( ( unused ) ) )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKBSZSET
|
||||
{
|
||||
size_t s_block_size = block_size;
|
||||
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
|
||||
if ( !dev->d_ops->ioctl( dev, BLKBSZSET, &s_block_size ) )
|
||||
{
|
||||
ntfs_log_debug( "Used BLKBSZSET to set block size to "
|
||||
"%d bytes.\n", block_size );
|
||||
return 0;
|
||||
|
@ -36,7 +36,8 @@
|
||||
*
|
||||
* Defined bits for the state field in the ntfs_device structure.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ND_Open, /* 1: Device is open. */
|
||||
ND_ReadOnly, /* 1: Device is read-only. */
|
||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||
@ -69,7 +70,8 @@ typedef enum {
|
||||
* The ntfs device structure defining all operations needed to access the low
|
||||
* level device underlying the ntfs volume.
|
||||
*/
|
||||
struct ntfs_device {
|
||||
struct ntfs_device
|
||||
{
|
||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||
unsigned long d_state; /* State of the device. */
|
||||
char *d_name; /* Name of device. */
|
||||
@ -85,7 +87,8 @@ struct stat;
|
||||
* The ntfs device operations defining all operations that can be performed on
|
||||
* the low level device described by an ntfs device structure.
|
||||
*/
|
||||
struct ntfs_device_operations {
|
||||
struct ntfs_device_operations
|
||||
{
|
||||
int ( *open )( struct ntfs_device *dev, int flags );
|
||||
int ( *close )( struct ntfs_device *dev );
|
||||
s64 ( *seek )( struct ntfs_device *dev, s64 offset, int whence );
|
||||
|
@ -45,7 +45,8 @@
|
||||
/**
|
||||
* struct hd_geometry -
|
||||
*/
|
||||
struct hd_geometry {
|
||||
struct hd_geometry
|
||||
{
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -60,7 +60,8 @@
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
static ntfschar logged_utility_stream_name[] = {
|
||||
static ntfschar logged_utility_stream_name[] =
|
||||
{
|
||||
const_cpu_to_le16( '$' ),
|
||||
const_cpu_to_le16( 'E' ),
|
||||
const_cpu_to_le16( 'F' ),
|
||||
@ -78,32 +79,43 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
||||
EFS_ATTR_HEADER *efs_info;
|
||||
s64 attr_size = 0;
|
||||
|
||||
if (ni) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
if ( ni )
|
||||
{
|
||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||
{
|
||||
efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni,
|
||||
AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0,
|
||||
&attr_size );
|
||||
if ( efs_info
|
||||
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
||||
if (attr_size <= (s64)size) {
|
||||
&& ( le32_to_cpu( efs_info->length ) == attr_size ) )
|
||||
{
|
||||
if ( attr_size <= ( s64 )size )
|
||||
{
|
||||
if ( value )
|
||||
memcpy( value, efs_info, attr_size );
|
||||
else {
|
||||
else
|
||||
{
|
||||
errno = EFAULT;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else
|
||||
if (size) {
|
||||
}
|
||||
else if ( size )
|
||||
{
|
||||
errno = ERANGE;
|
||||
attr_size = 0;
|
||||
}
|
||||
free ( efs_info );
|
||||
} else {
|
||||
if (efs_info) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( efs_info )
|
||||
{
|
||||
free( efs_info );
|
||||
ntfs_log_error( "Bad efs_info for inode %lld\n",
|
||||
( long long )ni->mft_no );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Could not get efsinfo"
|
||||
" for inode %lld\n",
|
||||
( long long )ni->mft_no );
|
||||
@ -111,7 +123,9 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
ntfs_log_trace( "Inode %lld is not encrypted\n",
|
||||
( long long )ni->mft_no );
|
||||
@ -145,45 +159,57 @@ static int fixup_loop(ntfs_inode *ni)
|
||||
int res = 0;
|
||||
|
||||
maxcnt = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
restart = FALSE;
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if (!ctx) {
|
||||
if ( !ctx )
|
||||
{
|
||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||
res = -1;
|
||||
}
|
||||
cnt = 0;
|
||||
while ( !restart && !res
|
||||
&& !ntfs_attr_lookup( AT_DATA, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
cnt++;
|
||||
a = ctx->attr;
|
||||
na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA,
|
||||
( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ),
|
||||
a->name_length );
|
||||
if (!na) {
|
||||
if ( !na )
|
||||
{
|
||||
ntfs_log_error( "can't open DATA Attribute\n" );
|
||||
res = -1;
|
||||
}
|
||||
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
|
||||
if ( na && !( ctx->attr->flags & ATTR_IS_ENCRYPTED ) )
|
||||
{
|
||||
if ( !NAttrNonResident( na )
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||
{
|
||||
/*
|
||||
* ntfs_attr_make_non_resident fails if there
|
||||
* is not enough space in the MFT record.
|
||||
* When this happens, force making non-resident
|
||||
* so that some other attribute is expelled.
|
||||
*/
|
||||
if (ntfs_attr_force_non_resident(na)) {
|
||||
if ( ntfs_attr_force_non_resident( na ) )
|
||||
{
|
||||
res = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* make sure there is some progress */
|
||||
if (cnt <= maxcnt) {
|
||||
if ( cnt <= maxcnt )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_error( "Multiple failure"
|
||||
" making non resident\n" );
|
||||
res = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
ctx = ( ntfs_attr_search_ctx* )NULL;
|
||||
restart = TRUE;
|
||||
@ -192,7 +218,8 @@ static int fixup_loop(ntfs_inode *ni)
|
||||
}
|
||||
}
|
||||
if ( !restart && !res
|
||||
&& ntfs_efs_fixup_attribute(ctx, na)) {
|
||||
&& ntfs_efs_fixup_attribute( ctx, na ) )
|
||||
{
|
||||
ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" );
|
||||
res = -1;
|
||||
}
|
||||
@ -201,7 +228,8 @@ static int fixup_loop(ntfs_inode *ni)
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
first = FALSE;
|
||||
} while (restart && !res);
|
||||
}
|
||||
while ( restart && !res );
|
||||
if ( ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
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;
|
||||
|
||||
res = 0;
|
||||
if (ni && value && size) {
|
||||
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
if ( ni && value && size )
|
||||
{
|
||||
if ( ni->flags & ( FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED ) )
|
||||
{
|
||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||
{
|
||||
ntfs_log_trace( "Inode %lld already encrypted\n",
|
||||
( long long )ni->mft_no );
|
||||
errno = EEXIST;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Possible problem : if encrypted file was
|
||||
* restored in a compressed directory, it was
|
||||
@ -244,13 +277,16 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
}
|
||||
info_header = ( const EFS_ATTR_HEADER* )value;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if (le32_to_cpu(info_header->length) != size) {
|
||||
if ( le32_to_cpu( info_header->length ) != size )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return ( -1 );
|
||||
}
|
||||
if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
(ntfschar*)NULL,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
( ntfschar* )NULL, 0 ) )
|
||||
{
|
||||
if ( !( flags & XATTR_REPLACE ) )
|
||||
{
|
||||
/*
|
||||
* no logged_utility_stream attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
@ -258,28 +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,
|
||||
logged_utility_stream_name, 4,
|
||||
( u8* )NULL, ( s64 )size );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
/*
|
||||
* open and update the existing efs data
|
||||
*/
|
||||
na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate( na, ( s64 )size );
|
||||
/* overwrite value if any */
|
||||
if (!res && value) {
|
||||
if ( !res && value )
|
||||
{
|
||||
written = ( int )ntfs_attr_pwrite( na,
|
||||
( s64 )0, ( s64 )size, value );
|
||||
if (written != (s64)size) {
|
||||
if ( written != ( s64 )size )
|
||||
{
|
||||
ntfs_log_error( "Failed to "
|
||||
"update efs data\n" );
|
||||
errno = EIO;
|
||||
@ -287,12 +331,15 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
}
|
||||
}
|
||||
ntfs_attr_close( na );
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
if ( !( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
/* iterate over AT_DATA attributes */
|
||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||
|
||||
@ -303,7 +350,9 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
NInoSetDirty( ni );
|
||||
NInoFileNameSetDirty( ni );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
@ -330,24 +379,31 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
ntfs_inode *ni;
|
||||
BOOL close_ctx = FALSE;
|
||||
|
||||
if (!na) {
|
||||
if ( !na )
|
||||
{
|
||||
ntfs_log_error( "no na specified for efs_fixup_attribute\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if (!ctx) {
|
||||
if ( !ctx )
|
||||
{
|
||||
ctx = ntfs_attr_get_search_ctx( na->ni, NULL );
|
||||
if (!ctx) {
|
||||
if ( !ctx )
|
||||
{
|
||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||
goto err_out;
|
||||
}
|
||||
close_ctx = TRUE;
|
||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
if (!NAttrNonResident(na)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !NAttrNonResident( na ) )
|
||||
{
|
||||
ntfs_log_error( "Cannot make non resident"
|
||||
" when a context has been allocated\n" );
|
||||
goto err_out;
|
||||
@ -356,19 +412,23 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
|
||||
/* no extra bytes are added to void attributes */
|
||||
oldsize = na->data_size;
|
||||
if (oldsize) {
|
||||
if ( oldsize )
|
||||
{
|
||||
/* make sure size is valid for a raw encrypted stream */
|
||||
if ((oldsize & 511) != 2) {
|
||||
if ( ( oldsize & 511 ) != 2 )
|
||||
{
|
||||
ntfs_log_error( "Bad raw encrypted stream\n" );
|
||||
goto err_out;
|
||||
}
|
||||
/* read padding length from last two bytes of attribute */
|
||||
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
|
||||
if ( ntfs_attr_pread( na, oldsize - 2, 2, &appended_bytes ) != 2 )
|
||||
{
|
||||
ntfs_log_error( "Error reading padding length\n" );
|
||||
goto err_out;
|
||||
}
|
||||
padding_length = le16_to_cpu( appended_bytes );
|
||||
if (padding_length > 511 || padding_length > na->data_size-2) {
|
||||
if ( padding_length > 511 || padding_length > na->data_size - 2 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_error( "invalid padding length %d for data_size %lld\n",
|
||||
padding_length, ( long long )oldsize );
|
||||
@ -380,11 +440,13 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
* for the last two bytes, but do not truncate to new size
|
||||
* to avoid losing useful data
|
||||
*/
|
||||
if (ntfs_attr_truncate(na, oldsize - 2)) {
|
||||
if ( ntfs_attr_truncate( na, oldsize - 2 ) )
|
||||
{
|
||||
ntfs_log_error( "Error truncating attribute\n" );
|
||||
goto err_out;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
newsize = 0;
|
||||
|
||||
/*
|
||||
@ -394,12 +456,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
* resident.
|
||||
*/
|
||||
if ( !NAttrNonResident( na )
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||
{
|
||||
if ( !close_ctx
|
||||
|| ntfs_attr_force_non_resident(na)) {
|
||||
|| ntfs_attr_force_non_resident( na ) )
|
||||
{
|
||||
ntfs_log_error( "Error making DATA attribute non-resident\n" );
|
||||
goto err_out;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* must reinitialize context after forcing
|
||||
* non-resident. We need a context for updating
|
||||
@ -408,14 +474,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
*/
|
||||
ntfs_attr_reinit_search_ctx( ctx );
|
||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
ni = na->ni;
|
||||
if (!na->name_len) {
|
||||
if ( !na->name_len )
|
||||
{
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
|
@ -80,32 +80,37 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Start the device interface and ensure that it is inserted
|
||||
if (!interface->startup()) {
|
||||
if ( !interface->startup() )
|
||||
{
|
||||
ntfs_log_perror( "device failed to start\n" );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (!interface->isInserted()) {
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
ntfs_log_perror( "device media is not inserted\n" );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device isn't already open (used by another volume?)
|
||||
if (NDevOpen(dev)) {
|
||||
if ( NDevOpen( dev ) )
|
||||
{
|
||||
ntfs_log_perror( "device is busy (already open)\n" );
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
@ -113,12 +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
|
||||
NTFS_BOOT_SECTOR boot;
|
||||
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
||||
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
||||
if ( interface->readSectors( fd->startSector, 1, &boot ) )
|
||||
{
|
||||
if ( !ntfs_boot_sector_is_ntfs( &boot ) )
|
||||
{
|
||||
errno = EINVALPART;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", fd->startSector );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@ -133,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 );
|
||||
|
||||
// Mark the device as read-only (if required)
|
||||
if (flags & O_RDONLY) {
|
||||
if ( flags & O_RDONLY )
|
||||
{
|
||||
NDevSetReadOnly( dev );
|
||||
}
|
||||
|
||||
@ -156,13 +166,15 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device is actually open
|
||||
if (!NDevOpen(dev)) {
|
||||
if ( !NDevOpen( dev ) )
|
||||
{
|
||||
ntfs_log_perror( "device is not open\n" );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@ -173,7 +185,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
NDevClearBlock( dev );
|
||||
|
||||
// Flush the device (if dirty and not read-only)
|
||||
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
||||
if ( NDevDirty( dev ) && !NDevReadOnly( dev ) )
|
||||
{
|
||||
ntfs_log_debug( "device is dirty, will now sync\n" );
|
||||
|
||||
// ...?
|
||||
@ -184,7 +197,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
}
|
||||
|
||||
// Flush and destroy the cache (if required)
|
||||
if (fd->cache) {
|
||||
if ( fd->cache )
|
||||
{
|
||||
_NTFS_cache_flush( fd->cache );
|
||||
_NTFS_cache_destructor( fd->cache );
|
||||
}
|
||||
@ -211,13 +225,15 @@ static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int wh
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the current position on the device (in bytes)
|
||||
switch(whence) {
|
||||
switch ( whence )
|
||||
{
|
||||
case SEEK_SET: fd->pos = MIN( MAX( offset, 0 ), fd->len ); break;
|
||||
case SEEK_CUR: fd->pos = MIN( MAX( fd->pos + offset, 0 ), fd->len ); break;
|
||||
case SEEK_END: fd->pos = MIN( MAX( fd->len + offset, 0 ), fd->len ); break;
|
||||
@ -267,14 +283,16 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -294,20 +312,24 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this read
|
||||
if (offset > 0) {
|
||||
if ( offset > 0 )
|
||||
{
|
||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
if (buffer_offset+count > fd->sectorSize) {
|
||||
if ( buffer_offset + count > fd->sectorSize )
|
||||
{
|
||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
|
||||
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
||||
|
||||
if((buffer_offset == 0) && (count % fd->sectorSize == 0)) {
|
||||
if ( ( buffer_offset == 0 ) && ( count % fd->sectorSize == 0 ) )
|
||||
{
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace( "direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buf ) )
|
||||
{
|
||||
ntfs_log_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@ -320,7 +342,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
|
||||
// Allocate a buffer to hold the read data
|
||||
buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize );
|
||||
if (!buffer) {
|
||||
if ( !buffer )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
@ -328,7 +351,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
// Read from the device
|
||||
ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_log_trace( "count: %d sec_count:%d fd->sectorSize: %d )\n", ( u32 )count, ( u32 )sec_count, ( u32 )fd->sectorSize );
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
@ -353,25 +377,29 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(count < 0 || offset < 0) {
|
||||
if ( count < 0 || offset < 0 )
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
@ -385,10 +413,12 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this write
|
||||
if (offset > 0) {
|
||||
if ( offset > 0 )
|
||||
{
|
||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
if ((buffer_offset+count) > fd->sectorSize) {
|
||||
if ( ( buffer_offset + count ) > fd->sectorSize )
|
||||
{
|
||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
|
||||
@ -397,7 +427,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
{
|
||||
// Write to the device
|
||||
ntfs_log_trace( "direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
|
||||
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buf ) )
|
||||
{
|
||||
ntfs_log_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@ -408,7 +439,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
{
|
||||
// Allocate a buffer to hold the write data
|
||||
buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize );
|
||||
if (!buffer) {
|
||||
if ( !buffer )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
@ -417,7 +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
|
||||
if ( buffer_offset != 0 )
|
||||
{
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, 1, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
@ -426,7 +459,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
}
|
||||
if ( ( buffer_offset + count ) % fd->sectorSize != 0 )
|
||||
{
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) {
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start + sec_count - 1, 1, buffer + ( ( sec_count - 1 ) * fd->sectorSize ) ) )
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
@ -439,7 +473,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
|
||||
// Write to the device
|
||||
ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
||||
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
@ -460,7 +495,8 @@ static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sect
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
@ -477,7 +513,8 @@ static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sec
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
@ -500,7 +537,8 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
ntfs_log_trace( "dev %p\n", dev );
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
@ -509,8 +547,10 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
NDevClearDirty( dev );
|
||||
|
||||
// Flush any sectors in the disc cache (if required)
|
||||
if (fd->cache) {
|
||||
if (!_NTFS_cache_flush(fd->cache)) {
|
||||
if ( fd->cache )
|
||||
{
|
||||
if ( !_NTFS_cache_flush( fd->cache ) )
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
@ -528,7 +568,8 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -565,17 +606,20 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Figure out which i/o control was requested
|
||||
switch (request) {
|
||||
switch ( request )
|
||||
{
|
||||
|
||||
// Get block device size (sectors)
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE: {
|
||||
case BLKGETSIZE:
|
||||
{
|
||||
*( u32* )argp = fd->sectorCount;
|
||||
return 0;
|
||||
}
|
||||
@ -583,7 +627,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64: {
|
||||
case BLKGETSIZE64:
|
||||
{
|
||||
*( u64* )argp = ( fd->sectorCount * fd->sectorSize );
|
||||
return 0;
|
||||
}
|
||||
@ -591,7 +636,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO: {
|
||||
case HDIO_GETGEO:
|
||||
{
|
||||
struct hd_geometry *geo = ( struct hd_geometry* )argp;
|
||||
geo->sectors = 0;
|
||||
geo->heads = 0;
|
||||
@ -603,7 +649,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET: {
|
||||
case BLKSSZGET:
|
||||
{
|
||||
*( int* )argp = fd->sectorSize;
|
||||
return 0;
|
||||
}
|
||||
@ -611,7 +658,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET: {
|
||||
case BLKBSZSET:
|
||||
{
|
||||
int sectorSize = *( int* )argp;
|
||||
fd->sectorSize = sectorSize;
|
||||
return 0;
|
||||
@ -619,7 +667,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
#endif
|
||||
|
||||
// Unimplemented ioctrl
|
||||
default: {
|
||||
default:
|
||||
{
|
||||
ntfs_log_perror( "Unimplemented ioctrl %i\n", request );
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
@ -633,7 +682,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
/**
|
||||
* Device operations for working with gekko style devices and files.
|
||||
*/
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops = {
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops =
|
||||
{
|
||||
.open = ntfs_device_gekko_io_open,
|
||||
.close = ntfs_device_gekko_io_close,
|
||||
.seek = ntfs_device_gekko_io_seek,
|
||||
|
@ -33,7 +33,8 @@
|
||||
/**
|
||||
* gekko_fd - Gekko device driver descriptor
|
||||
*/
|
||||
typedef struct _gekko_fd {
|
||||
typedef struct _gekko_fd
|
||||
{
|
||||
const DISC_INTERFACE* interface; /* Device disc interface */
|
||||
sec_t startSector; /* LBA of partition start */
|
||||
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
||||
|
@ -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 ),
|
||||
1, icx->block_size, ib );
|
||||
if (ret != 1) {
|
||||
if ( ret != 1 )
|
||||
{
|
||||
ntfs_log_perror( "Failed to write index block %lld, inode %llu",
|
||||
( long long )vcn, ( unsigned long long )icx->ni->mft_no );
|
||||
return STATUS_ERROR;
|
||||
@ -123,7 +124,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
||||
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@ -131,7 +133,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
||||
ni = ni->base_ni;
|
||||
icx = ntfs_calloc( sizeof( ntfs_index_context ) );
|
||||
if ( icx )
|
||||
*icx = (ntfs_index_context) {
|
||||
*icx = ( ntfs_index_context )
|
||||
{
|
||||
.ni = ni,
|
||||
.name = name,
|
||||
.name_len = name_len,
|
||||
@ -149,8 +152,10 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
|
||||
if ( icx->actx )
|
||||
ntfs_attr_put_search_ctx( icx->actx );
|
||||
|
||||
if (!icx->is_in_root) {
|
||||
if (icx->ib_dirty) {
|
||||
if ( !icx->is_in_root )
|
||||
{
|
||||
if ( icx->ib_dirty )
|
||||
{
|
||||
/* FIXME: Error handling!!! */
|
||||
ntfs_ib_write( icx, icx->ib );
|
||||
}
|
||||
@ -184,7 +189,8 @@ void ntfs_index_ctx_reinit(ntfs_index_context *icx)
|
||||
|
||||
ntfs_index_ctx_free( icx );
|
||||
|
||||
*icx = (ntfs_index_context) {
|
||||
*icx = ( ntfs_index_context )
|
||||
{
|
||||
.ni = icx->ni,
|
||||
.name = icx->name,
|
||||
.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 );
|
||||
|
||||
while (tmp != ie) {
|
||||
while ( tmp != ie )
|
||||
{
|
||||
ie_prev = tmp;
|
||||
tmp = ntfs_ie_get_next( tmp );
|
||||
}
|
||||
@ -293,7 +300,8 @@ void ntfs_ih_filename_dump(INDEX_HEADER *ih)
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
|
||||
ie = ntfs_ie_get_first( ih );
|
||||
while (!ntfs_ie_end(ie)) {
|
||||
while ( !ntfs_ie_end( ie ) )
|
||||
{
|
||||
ntfs_ie_filename_dump( ie );
|
||||
ie = ntfs_ie_get_next( ie );
|
||||
}
|
||||
@ -380,7 +388,8 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
|
||||
size -= sizeof( VCN );
|
||||
|
||||
dup = ntfs_malloc( size );
|
||||
if (dup) {
|
||||
if ( dup )
|
||||
{
|
||||
memcpy( dup, ie, size );
|
||||
dup->ie_flags &= ~INDEX_ENTRY_NODE;
|
||||
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" );
|
||||
|
||||
if (!ntfs_is_indx_record(ib->magic)) {
|
||||
if ( !ntfs_is_indx_record( ib->magic ) )
|
||||
{
|
||||
|
||||
ntfs_log_error( "Corrupt index block signature: vcn %lld inode "
|
||||
"%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;
|
||||
}
|
||||
|
||||
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 "
|
||||
"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;
|
||||
}
|
||||
|
||||
if (ib_size != icx->block_size) {
|
||||
if ( ib_size != icx->block_size )
|
||||
{
|
||||
|
||||
ntfs_log_error( "Corrupt index block : VCN (%lld) of inode %llu "
|
||||
"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;
|
||||
|
||||
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" );
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
a = ( *ctx )->attr;
|
||||
if (a->non_resident) {
|
||||
if ( a->non_resident )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "Non-resident $INDEX_ROOT detected" );
|
||||
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 ) );
|
||||
err_out:
|
||||
if (!ir) {
|
||||
if ( !ir )
|
||||
{
|
||||
ntfs_attr_put_search_ctx( *ctx );
|
||||
*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
|
||||
* 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. */
|
||||
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;
|
||||
ntfs_log_error( "Index entry out of bounds in inode "
|
||||
"%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
|
||||
* 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" );
|
||||
errno = EOPNOTSUPP;
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
rc = icx->collate( icx->ni->vol, key, key_len,
|
||||
&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 "
|
||||
"contains invalid characters?\n" );
|
||||
errno = ERANGE;
|
||||
@ -538,7 +557,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
|
||||
if ( rc == -1 )
|
||||
break;
|
||||
|
||||
if (!rc) {
|
||||
if ( !rc )
|
||||
{
|
||||
*ie_out = ie;
|
||||
errno = 0;
|
||||
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,
|
||||
* 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" );
|
||||
*ie_out = ie;
|
||||
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. */
|
||||
*vcn = ntfs_ie_get_vcn( ie );
|
||||
if (*vcn < 0) {
|
||||
if ( *vcn < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "Negative vcn in inode %llu",
|
||||
( 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;
|
||||
|
||||
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 "
|
||||
"%llu", ( unsigned long long )ni->mft_no );
|
||||
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 );
|
||||
|
||||
ret = ntfs_attr_mst_pread( icx->ia_na, pos, 1, icx->block_size, ( u8 * )dst );
|
||||
if (ret != 1) {
|
||||
if ( ret != 1 )
|
||||
{
|
||||
if ( ret == -1 )
|
||||
ntfs_log_perror( "Failed to read index block" );
|
||||
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 )
|
||||
{
|
||||
icx->pindex++;
|
||||
if (icx->pindex >= MAX_PARENT_VCN) {
|
||||
if ( icx->pindex >= MAX_PARENT_VCN )
|
||||
{
|
||||
errno = EOPNOTSUPP;
|
||||
ntfs_log_perror( "Index is over %d level deep", MAX_PARENT_VCN );
|
||||
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 )
|
||||
{
|
||||
icx->pindex--;
|
||||
if (icx->pindex < 0) {
|
||||
if ( icx->pindex < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "Corrupt index pointer (%d)", icx->pindex );
|
||||
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" );
|
||||
|
||||
if (!key || key_len <= 0) {
|
||||
if ( !key || key_len <= 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "key: %p key_len: %d", key, key_len );
|
||||
return -1;
|
||||
}
|
||||
|
||||
ir = ntfs_ir_lookup( ni, icx->name, icx->name_len, &icx->actx );
|
||||
if (!ir) {
|
||||
if ( !ir )
|
||||
{
|
||||
if ( errno == ENOENT )
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
ntfs_log_perror( "Index block size (%d) is smaller than the "
|
||||
"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;
|
||||
/* get the appropriate collation function */
|
||||
icx->collate = ntfs_get_collate_function( ir->collation_rule );
|
||||
if (!icx->collate) {
|
||||
if ( !icx->collate )
|
||||
{
|
||||
err = errno = EOPNOTSUPP;
|
||||
ntfs_log_perror( "Unknown collation rule 0x%x",
|
||||
( 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.
|
||||
*/
|
||||
ret = ntfs_ie_lookup( key, key_len, icx, &ir->index, &vcn, &ie );
|
||||
if (ret == STATUS_ERROR) {
|
||||
if ( ret == STATUS_ERROR )
|
||||
{
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
icx->ir = ir;
|
||||
|
||||
if (ret != STATUS_KEEP_SEARCHING) {
|
||||
if ( ret != STATUS_KEEP_SEARCHING )
|
||||
{
|
||||
/* STATUS_OK or STATUS_NOT_FOUND */
|
||||
err = errno;
|
||||
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;
|
||||
|
||||
ib = ntfs_malloc( icx->block_size );
|
||||
if (!ib) {
|
||||
if ( !ib )
|
||||
{
|
||||
err = errno;
|
||||
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:
|
||||
|
||||
icx->parent_vcn[icx->pindex] = old_vcn;
|
||||
if (ntfs_icx_parent_inc(icx)) {
|
||||
if ( ntfs_icx_parent_inc( icx ) )
|
||||
{
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
@ -759,7 +793,8 @@ descend_into_child_node:
|
||||
goto err_out;
|
||||
|
||||
ret = ntfs_ie_lookup( key, key_len, icx, &ib->index, &vcn, &ie );
|
||||
if (ret != STATUS_KEEP_SEARCHING) {
|
||||
if ( ret != STATUS_KEEP_SEARCHING )
|
||||
{
|
||||
err = errno;
|
||||
if ( ret == STATUS_ERROR )
|
||||
goto err_out;
|
||||
@ -771,7 +806,8 @@ descend_into_child_node:
|
||||
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 "
|
||||
"node in inode 0x%llx.\n",
|
||||
( unsigned long long )ni->mft_no );
|
||||
@ -790,7 +826,8 @@ done:
|
||||
icx->data = ( u8 * )ie + offsetof( INDEX_ENTRY, key );
|
||||
icx->data_len = le16_to_cpu( ie->key_length );
|
||||
ntfs_log_trace( "Done.\n" );
|
||||
if (err) {
|
||||
if ( err )
|
||||
{
|
||||
errno = err;
|
||||
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_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 );
|
||||
i++;
|
||||
}
|
||||
@ -883,7 +921,8 @@ static int ntfs_ibm_add(ntfs_index_context *icx)
|
||||
*/
|
||||
memset( bmp, 0, sizeof( bmp ) );
|
||||
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" );
|
||||
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 );
|
||||
|
||||
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" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
if (na->data_size < bpos + 1) {
|
||||
if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) {
|
||||
if ( set )
|
||||
{
|
||||
if ( na->data_size < bpos + 1 )
|
||||
{
|
||||
if ( ntfs_attr_truncate( na, ( na->data_size + 8 ) & ~7 ) )
|
||||
{
|
||||
ntfs_log_perror( "Failed to truncate AT_BITMAP" );
|
||||
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" );
|
||||
goto err_na;
|
||||
}
|
||||
@ -927,7 +971,8 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
|
||||
else
|
||||
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" );
|
||||
goto err_na;
|
||||
}
|
||||
@ -962,13 +1007,16 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx)
|
||||
if ( !bm )
|
||||
return ( VCN ) - 1;
|
||||
|
||||
for (byte = 0; byte < size; byte++) {
|
||||
for ( byte = 0; byte < size; byte++ )
|
||||
{
|
||||
|
||||
if ( bm[byte] == 255 )
|
||||
continue;
|
||||
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
if (!(bm[byte] & (1 << bit))) {
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( !( bm[byte] & ( 1 << bit ) ) )
|
||||
{
|
||||
vcn = ntfs_ibm_pos_to_vcn( icx, byte * 8 + bit );
|
||||
goto out;
|
||||
}
|
||||
@ -1030,7 +1078,8 @@ static void ntfs_ir_nill(INDEX_ROOT *ir)
|
||||
/*
|
||||
* 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 ) );
|
||||
ie_last = ( INDEX_ENTRY * )ies_start;
|
||||
}
|
||||
@ -1098,10 +1147,12 @@ static int ntfs_ia_add(ntfs_index_context *icx)
|
||||
if ( ntfs_ibm_add( icx ) )
|
||||
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,
|
||||
icx->name_len, NULL, 0)) {
|
||||
icx->name_len, NULL, 0 ) )
|
||||
{
|
||||
ntfs_log_perror( "Failed to add AT_INDEX_ALLOCATION" );
|
||||
return -1;
|
||||
}
|
||||
@ -1142,7 +1193,8 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
|
||||
goto clear_bmp;
|
||||
|
||||
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" );
|
||||
goto clear_bmp;
|
||||
}
|
||||
@ -1200,7 +1252,8 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
|
||||
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" );
|
||||
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.
|
||||
*/
|
||||
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 );
|
||||
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 );
|
||||
|
||||
} else if (ret == STATUS_ERROR)
|
||||
}
|
||||
else if ( ret == STATUS_ERROR )
|
||||
ntfs_log_perror( "Failed to truncate INDEX_ROOT" );
|
||||
|
||||
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" );
|
||||
|
||||
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 );
|
||||
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 );
|
||||
allocated_size = le32_to_cpu( ib->index.allocated_size );
|
||||
/* 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 );
|
||||
if ( err == STATUS_OK )
|
||||
err = STATUS_KEEP_SEARCHING;
|
||||
@ -1405,7 +1462,8 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
|
||||
if ( new_vcn == -1 )
|
||||
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 );
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
@ -1415,7 +1473,8 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
|
||||
else
|
||||
ret = ntfs_ib_insert( icx, median, new_vcn );
|
||||
|
||||
if (ret != STATUS_OK) {
|
||||
if ( ret != STATUS_OK )
|
||||
{
|
||||
ntfs_ibm_clear( icx, new_vcn );
|
||||
return ret;
|
||||
}
|
||||
@ -1441,14 +1500,17 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
|
||||
*/
|
||||
#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;
|
||||
ntfs_log_perror( "Index already have such entry" );
|
||||
goto err_out;
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
if ( errno != ENOENT )
|
||||
{
|
||||
ntfs_log_perror( "Failed to find place for new entry" );
|
||||
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",
|
||||
allocated_size, new_size );
|
||||
|
||||
if (icx->is_in_root) {
|
||||
if ( icx->is_in_root )
|
||||
{
|
||||
if ( ntfs_ir_make_space( icx, new_size ) == STATUS_ERROR )
|
||||
goto err_out;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ntfs_ib_split( icx, icx->ib ) == STATUS_ERROR )
|
||||
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" );
|
||||
|
||||
if (!ni || !fn) {
|
||||
if ( !ni || !fn )
|
||||
{
|
||||
ntfs_log_error( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
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 )
|
||||
ntfs_inode_mark_dirty( icx->actx->ntfs_ino );
|
||||
else
|
||||
if (ntfs_ib_write(icx, ib))
|
||||
else if ( ntfs_ib_write( icx, ib ) )
|
||||
goto out;
|
||||
|
||||
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 )
|
||||
parent_ih = &icx->ir->index;
|
||||
else {
|
||||
else
|
||||
{
|
||||
ib = ntfs_malloc( icx->block_size );
|
||||
if ( !ib )
|
||||
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 ) );
|
||||
if (!ntfs_ie_end(ie)) {
|
||||
if ( !ntfs_ie_end( ie ) )
|
||||
{
|
||||
ret = ntfs_ih_takeout( icx, parent_ih, ie, ib );
|
||||
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 );
|
||||
goto ok;
|
||||
}
|
||||
@ -1670,7 +1739,8 @@ static int ntfs_index_rm_node(ntfs_index_context *icx)
|
||||
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
|
||||
if (!icx->ia_na) {
|
||||
if ( !icx->ia_na )
|
||||
{
|
||||
icx->ia_na = ntfs_ia_open( icx, icx->ni );
|
||||
if ( !icx->ia_na )
|
||||
return STATUS_ERROR;
|
||||
@ -1699,7 +1769,8 @@ descend:
|
||||
if ( ( ib->index.ih_flags & NODE_MASK ) == INDEX_NODE )
|
||||
goto descend;
|
||||
|
||||
if (ntfs_ih_zero_entry(&ib->index)) {
|
||||
if ( ntfs_ih_zero_entry( &ib->index ) )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Empty index block" );
|
||||
goto out;
|
||||
@ -1721,8 +1792,10 @@ descend:
|
||||
|
||||
delta = le16_to_cpu( ie->length ) - le16_to_cpu( icx->entry->length );
|
||||
new_size = le32_to_cpu( ih->index_length ) + delta;
|
||||
if (delta > 0) {
|
||||
if (icx->is_in_root) {
|
||||
if ( delta > 0 )
|
||||
{
|
||||
if ( icx->is_in_root )
|
||||
{
|
||||
ret = ntfs_ir_make_space( icx, new_size );
|
||||
if ( ret != STATUS_OK )
|
||||
goto out2;
|
||||
@ -1730,7 +1803,9 @@ descend:
|
||||
ih = &icx->ir->index;
|
||||
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;
|
||||
ret = ntfs_ib_split( icx, icx->ib );
|
||||
if ( ret == STATUS_OK )
|
||||
@ -1742,20 +1817,22 @@ descend:
|
||||
ntfs_ie_delete( ih, entry );
|
||||
ntfs_ie_insert( ih, ie, entry );
|
||||
|
||||
if (icx->is_in_root) {
|
||||
if ( icx->is_in_root )
|
||||
{
|
||||
if ( ntfs_ir_truncate( icx, new_size ) )
|
||||
goto out2;
|
||||
} else
|
||||
if (ntfs_icx_ib_write(icx))
|
||||
}
|
||||
else if ( ntfs_icx_ib_write( icx ) )
|
||||
goto out2;
|
||||
|
||||
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 ) )
|
||||
goto out2;
|
||||
} else
|
||||
if (ntfs_ib_write(icx, ib))
|
||||
}
|
||||
else if ( ntfs_ib_write( icx, ib ) )
|
||||
goto out2;
|
||||
|
||||
ret = STATUS_OK;
|
||||
@ -1784,7 +1861,8 @@ int ntfs_index_rm(ntfs_index_context *icx)
|
||||
|
||||
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" );
|
||||
errno = EINVAL;
|
||||
goto err_out;
|
||||
@ -1794,22 +1872,28 @@ int ntfs_index_rm(ntfs_index_context *icx)
|
||||
else
|
||||
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 );
|
||||
|
||||
} 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 );
|
||||
|
||||
if (icx->is_in_root) {
|
||||
if ( icx->is_in_root )
|
||||
{
|
||||
err = ntfs_ir_truncate( icx, le32_to_cpu( ih->index_length ) );
|
||||
if ( err != STATUS_OK )
|
||||
goto err_out;
|
||||
} else
|
||||
if (ntfs_icx_ib_write(icx))
|
||||
}
|
||||
else if ( ntfs_icx_ib_write( icx ) )
|
||||
goto err_out;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ntfs_index_rm_leaf( icx ) )
|
||||
goto err_out;
|
||||
}
|
||||
@ -1830,14 +1914,16 @@ int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
if ( !icx )
|
||||
return -1;
|
||||
|
||||
while (1) {
|
||||
while ( 1 )
|
||||
{
|
||||
|
||||
if ( ntfs_index_lookup( key, keylen, icx ) )
|
||||
goto err_out;
|
||||
|
||||
if ( ( ( ( FILE_NAME_ATTR * )icx->data )->file_attributes &
|
||||
FILE_ATTR_REPARSE_POINT )
|
||||
&& !ntfs_possible_symlink(ni)) {
|
||||
&& !ntfs_possible_symlink( ni ) )
|
||||
{
|
||||
errno = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
@ -1910,9 +1996,11 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
|
||||
s64 vcn;
|
||||
|
||||
entry = ie;
|
||||
do {
|
||||
do
|
||||
{
|
||||
vcn = ntfs_ie_get_vcn( entry );
|
||||
if (ictx->is_in_root) {
|
||||
if ( ictx->is_in_root )
|
||||
{
|
||||
|
||||
/* 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->pindex = 1;
|
||||
ictx->is_in_root = FALSE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* 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_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 );
|
||||
entry = ictx->entry;
|
||||
} else
|
||||
}
|
||||
else
|
||||
entry = ( INDEX_ENTRY* )NULL;
|
||||
} while (entry && (entry->ie_flags & INDEX_ENTRY_NODE));
|
||||
}
|
||||
while ( entry && ( entry->ie_flags & INDEX_ENTRY_NODE ) );
|
||||
return ( entry );
|
||||
}
|
||||
|
||||
@ -1950,10 +2043,13 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
|
||||
s64 vcn;
|
||||
|
||||
entry = ie;
|
||||
if (ictx->pindex > 0) {
|
||||
do {
|
||||
if ( ictx->pindex > 0 )
|
||||
{
|
||||
do
|
||||
{
|
||||
ictx->pindex--;
|
||||
if (!ictx->pindex) {
|
||||
if ( !ictx->pindex )
|
||||
{
|
||||
|
||||
/* we have reached the root */
|
||||
|
||||
@ -1972,20 +2068,26 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
|
||||
ictx->parent_pos[ictx->pindex] );
|
||||
else
|
||||
entry = ( INDEX_ENTRY* )NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* up into non-root node */
|
||||
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(
|
||||
&ictx->ib->index,
|
||||
ictx->parent_pos[ictx->pindex] );
|
||||
} else
|
||||
}
|
||||
else
|
||||
entry = ( INDEX_ENTRY* )NULL;
|
||||
}
|
||||
ictx->entry = entry;
|
||||
} while (entry && (ictx->pindex > 0)
|
||||
}
|
||||
while ( entry && ( ictx->pindex > 0 )
|
||||
&& ( entry->ie_flags & INDEX_ENTRY_END ) );
|
||||
} else
|
||||
}
|
||||
else
|
||||
entry = ( INDEX_ENTRY* )NULL;
|
||||
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 )
|
||||
next = ntfs_index_walk_up( ie, ictx );
|
||||
else {
|
||||
else
|
||||
{
|
||||
/*
|
||||
* get next entry in same node
|
||||
* 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 */
|
||||
|
||||
if (flags & INDEX_ENTRY_NODE) {
|
||||
if ( flags & INDEX_ENTRY_NODE )
|
||||
{
|
||||
next = ntfs_index_walk_down( next, ictx );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,8 @@ typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
||||
* the call to ntfs_index_ctx_put() to ensure that the changes are written
|
||||
* to disk.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
|
@ -166,7 +166,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
||||
int olderrno;
|
||||
|
||||
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
|
||||
if (!vol) {
|
||||
if ( !vol )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -175,7 +176,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
||||
goto out;
|
||||
if ( ntfs_file_record_read( vol, mref, &ni->mrec, NULL ) )
|
||||
goto err_out;
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) {
|
||||
if ( !( ni->mrec->flags & MFT_RECORD_IN_USE ) )
|
||||
{
|
||||
errno = ENOENT;
|
||||
goto err_out;
|
||||
}
|
||||
@ -185,7 +187,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
||||
goto err_out;
|
||||
/* Receive some basic information about inode. */
|
||||
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 )
|
||||
ntfs_log_perror( "No STANDARD_INFORMATION in base record"
|
||||
" %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 */
|
||||
/* length may be seen as 72 (v1.x) or 96 (v3.x) */
|
||||
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 );
|
||||
ni->owner_id = std_info->owner_id;
|
||||
ni->security_id = std_info->security_id;
|
||||
ni->quota_charged = std_info->quota_charged;
|
||||
ni->usn = std_info->usn;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
clear_nino_flag( ni, v3_Extensions );
|
||||
ni->owner_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. */
|
||||
olderrno = errno;
|
||||
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 )
|
||||
goto put_err_out;
|
||||
/* 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 );
|
||||
if ( !l )
|
||||
goto put_err_out;
|
||||
if (l > 0x40000) {
|
||||
if ( l > 0x40000 )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Too large attrlist attribute (%lld), inode "
|
||||
"%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 );
|
||||
if ( !l )
|
||||
goto put_err_out;
|
||||
if (l != ni->attr_list_size) {
|
||||
if ( l != ni->attr_list_size )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Unexpected attrlist size (%lld <> %u), inode "
|
||||
"%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:
|
||||
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 )
|
||||
goto put_err_out;
|
||||
/* Directory or special file. */
|
||||
/* restore previous errno to avoid misinterpretation */
|
||||
errno = olderrno;
|
||||
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 );
|
||||
if ( ctx->attr->flags &
|
||||
( ATTR_IS_COMPRESSED | ATTR_IS_SPARSE ) )
|
||||
@ -266,7 +279,9 @@ get_size:
|
||||
else
|
||||
ni->allocated_size = sle64_to_cpu(
|
||||
ctx->attr->allocated_size );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ni->data_size = le32_to_cpu( ctx->attr->value_length );
|
||||
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 );
|
||||
|
||||
/* If we have dirty metadata, write it out. */
|
||||
if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
|
||||
if (ntfs_inode_sync(ni)) {
|
||||
if ( NInoDirty( ni ) || NInoAttrListDirty( ni ) )
|
||||
{
|
||||
if ( ntfs_inode_sync( ni ) )
|
||||
{
|
||||
if ( errno != EIO )
|
||||
errno = EBUSY;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
/* Is this a base inode with mapped extent inodes? */
|
||||
if (ni->nr_extents > 0) {
|
||||
while (ni->nr_extents > 0) {
|
||||
if (ntfs_inode_real_close(ni->extent_nis[0])) {
|
||||
if ( ni->nr_extents > 0 )
|
||||
{
|
||||
while ( ni->nr_extents > 0 )
|
||||
{
|
||||
if ( ntfs_inode_real_close( ni->extent_nis[0] ) )
|
||||
{
|
||||
if ( errno != EIO )
|
||||
errno = EBUSY;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
} else if (ni->nr_extents == -1) {
|
||||
}
|
||||
else if ( ni->nr_extents == -1 )
|
||||
{
|
||||
ntfs_inode **tmp_nis;
|
||||
ntfs_inode *base_ni;
|
||||
s32 i;
|
||||
@ -346,7 +368,8 @@ int ntfs_inode_real_close(ntfs_inode *ni)
|
||||
* base inode before destroying it.
|
||||
*/
|
||||
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;
|
||||
if ( tmp_nis[i] != ni )
|
||||
continue;
|
||||
@ -355,7 +378,8 @@ int ntfs_inode_real_close(ntfs_inode *ni)
|
||||
( base_ni->nr_extents - i - 1 ) *
|
||||
sizeof( ntfs_inode * ) );
|
||||
/* Buffer should be for multiple of four extents. */
|
||||
if ((--base_ni->nr_extents) & 3) {
|
||||
if ( ( --base_ni->nr_extents ) & 3 )
|
||||
{
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
@ -363,14 +387,17 @@ int ntfs_inode_real_close(ntfs_inode *ni)
|
||||
* ElectricFence is unhappy with realloc(x,0) as free(x)
|
||||
* thus we explicitly separate these two cases.
|
||||
*/
|
||||
if (base_ni->nr_extents) {
|
||||
if ( base_ni->nr_extents )
|
||||
{
|
||||
/* Resize the memory buffer. */
|
||||
tmp_nis = realloc( tmp_nis, base_ni->nr_extents *
|
||||
sizeof( ntfs_inode * ) );
|
||||
/* Ignore errors, they don't really matter. */
|
||||
if ( tmp_nis )
|
||||
base_ni->extent_nis = tmp_nis;
|
||||
} else if (tmp_nis) {
|
||||
}
|
||||
else if ( tmp_nis )
|
||||
{
|
||||
free( tmp_nis );
|
||||
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;
|
||||
cached = ( struct CACHED_NIDATA* )ntfs_fetch_cache( vol->nidata_cache,
|
||||
GENERIC( &item ), idata_cache_compare );
|
||||
if (cached) {
|
||||
if ( cached )
|
||||
{
|
||||
ni = cached->ni;
|
||||
/* do not keep open entries in cache */
|
||||
ntfs_remove_cache( vol->nidata_cache,
|
||||
( struct CACHED_GENERIC* )cached, 0 );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ni = ntfs_inode_real_open( vol, mref );
|
||||
}
|
||||
#else
|
||||
@ -504,24 +534,29 @@ int ntfs_inode_close(ntfs_inode *ni)
|
||||
BOOL dirty;
|
||||
struct CACHED_NIDATA item;
|
||||
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
debug_double_inode( ni->mft_no, 0 );
|
||||
/* do not cache system files : could lead to double entries */
|
||||
if ( ni->vol && ni->vol->nidata_cache
|
||||
&& ( ( ni->mft_no == FILE_root )
|
||||
|| ( ( 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. */
|
||||
dirty = NInoDirty( ni ) || NInoAttrListDirty( ni );
|
||||
if (dirty) {
|
||||
if ( dirty )
|
||||
{
|
||||
res = ntfs_inode_sync( ni );
|
||||
/* do a real close if sync failed */
|
||||
if ( res )
|
||||
ntfs_inode_real_close( ni );
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = 0;
|
||||
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
/* feed idata into cache */
|
||||
item.inum = ni->mft_no;
|
||||
item.ni = ni;
|
||||
@ -531,11 +566,14 @@ int ntfs_inode_close(ntfs_inode *ni)
|
||||
ntfs_enter_cache( ni->vol->nidata_cache,
|
||||
GENERIC( &item ), idata_cache_compare );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* cache not ready or system file, really close */
|
||||
res = ntfs_inode_real_close( ni );
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = 0;
|
||||
#else
|
||||
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;
|
||||
int i;
|
||||
|
||||
if (!base_ni) {
|
||||
if ( !base_ni )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
||||
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 );
|
||||
|
||||
/* 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;
|
||||
for (i = 0; i < base_ni->nr_extents; i++) {
|
||||
for ( i = 0; i < base_ni->nr_extents; i++ )
|
||||
{
|
||||
u16 seq_no;
|
||||
|
||||
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. */
|
||||
seq_no = MSEQNO_LE( mref );
|
||||
if ( seq_no && seq_no != le16_to_cpu(
|
||||
ni->mrec->sequence_number)) {
|
||||
ni->mrec->sequence_number ) )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Found stale extent mft "
|
||||
"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->base_ni = base_ni;
|
||||
/* 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 * );
|
||||
|
||||
extent_nis = ntfs_malloc( i );
|
||||
if ( !extent_nis )
|
||||
goto err_out;
|
||||
if (base_ni->nr_extents) {
|
||||
if ( base_ni->nr_extents )
|
||||
{
|
||||
memcpy( extent_nis, base_ni->extent_nis,
|
||||
i - 4 * sizeof( ntfs_inode * ) );
|
||||
free( base_ni->extent_nis );
|
||||
@ -651,7 +695,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
u64 prev_attached = 0;
|
||||
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -666,7 +711,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
||||
if ( !NInoAttrList( ni ) )
|
||||
return 0;
|
||||
|
||||
if (!ni->attr_list) {
|
||||
if ( !ni->attr_list )
|
||||
{
|
||||
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -675,10 +721,13 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
||||
/* Walk through attribute list and attach all extents. */
|
||||
errno = 0;
|
||||
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 ) &&
|
||||
prev_attached != MREF_LE(ale->mft_reference)) {
|
||||
if (!ntfs_extent_inode_open(ni, ale->mft_reference)) {
|
||||
prev_attached != MREF_LE( ale->mft_reference ) )
|
||||
{
|
||||
if ( !ntfs_extent_inode_open( ni, ale->mft_reference ) )
|
||||
{
|
||||
ntfs_log_trace( "Couldn't attach extent inode.\n" );
|
||||
return -1;
|
||||
}
|
||||
@ -708,7 +757,8 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
|
||||
if ( !ctx )
|
||||
return -1;
|
||||
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)",
|
||||
( long long )ni->mft_no );
|
||||
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 +
|
||||
le16_to_cpu( ctx->attr->value_offset ) );
|
||||
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->last_data_change_time = ni->last_data_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 ) ) )
|
||||
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->security_id = ni->security_id;
|
||||
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 );
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if (!ctx) {
|
||||
if ( !ctx )
|
||||
{
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
/* Collect the reparse tag, if any */
|
||||
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,
|
||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
rpp = ( REPARSE_POINT* )( ( u8 * )ctx->attr +
|
||||
le16_to_cpu( ctx->attr->value_offset ) );
|
||||
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 );
|
||||
}
|
||||
/* 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 +
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
index_ni = ni;
|
||||
} else
|
||||
if (dir_ni)
|
||||
}
|
||||
else if ( dir_ni )
|
||||
index_ni = dir_ni;
|
||||
else
|
||||
index_ni = ntfs_inode_open( ni->vol,
|
||||
le64_to_cpu( fn->parent_directory ) );
|
||||
if (!index_ni) {
|
||||
if ( !index_ni )
|
||||
{
|
||||
if ( !err )
|
||||
err = errno;
|
||||
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;
|
||||
}
|
||||
ictx = ntfs_index_ctx_get( index_ni, NTFS_INDEX_I30, 4 );
|
||||
if (!ictx) {
|
||||
if ( !ictx )
|
||||
{
|
||||
if ( !err )
|
||||
err = errno;
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) {
|
||||
if (!err) {
|
||||
if ( ntfs_index_lookup( fn, sizeof( FILE_NAME_ATTR ), ictx ) )
|
||||
{
|
||||
if ( !err )
|
||||
{
|
||||
if ( errno == ENOENT )
|
||||
err = EIO;
|
||||
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 )
|
||||
fnx->data_size = fnx->allocated_size
|
||||
= const_cpu_to_le64( 0 );
|
||||
else {
|
||||
else
|
||||
{
|
||||
fnx->allocated_size = cpu_to_sle64( ni->allocated_size );
|
||||
fnx->data_size = cpu_to_sle64( ni->data_size );
|
||||
}
|
||||
/* update or clear the reparse tag in the index */
|
||||
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->last_data_change_time = ni->last_data_change_time;
|
||||
fnx->last_mft_change_time = ni->last_mft_change_time;
|
||||
fnx->last_access_time = ni->last_access_time;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fnx->creation_time = fn->creation_time;
|
||||
fnx->last_data_change_time = fn->last_data_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;
|
||||
}
|
||||
/* Check for real error occurred. */
|
||||
if (errno != ENOENT) {
|
||||
if ( errno != ENOENT )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_perror( "Attribute lookup failed, inode %lld",
|
||||
( long long )ni->mft_no );
|
||||
goto err_out;
|
||||
}
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
if (err) {
|
||||
if ( err )
|
||||
{
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
@ -905,7 +972,8 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
{
|
||||
int ret = 0;
|
||||
int err = 0;
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_error( "Failed to sync NULL inode\n" );
|
||||
return -1;
|
||||
@ -915,8 +983,10 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
|
||||
/* Update STANDARD_INFORMATION. */
|
||||
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
||||
ntfs_inode_sync_standard_information(ni)) {
|
||||
if (!err || errno == EIO) {
|
||||
ntfs_inode_sync_standard_information( ni ) )
|
||||
{
|
||||
if ( !err || errno == EIO )
|
||||
{
|
||||
err = errno;
|
||||
if ( err != EIO )
|
||||
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. */
|
||||
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
||||
NInoFileNameTestAndClearDirty( ni ) &&
|
||||
ntfs_inode_sync_file_name(ni, dir_ni)) {
|
||||
if (!err || errno == EIO) {
|
||||
ntfs_inode_sync_file_name( ni, dir_ni ) )
|
||||
{
|
||||
if ( !err || errno == EIO )
|
||||
{
|
||||
err = errno;
|
||||
if ( err != EIO )
|
||||
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. */
|
||||
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
||||
NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) {
|
||||
NInoAttrList( ni ) && NInoAttrListTestAndClearDirty( ni ) )
|
||||
{
|
||||
ntfs_attr *na;
|
||||
|
||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||
if (!na) {
|
||||
if (!err || errno == EIO) {
|
||||
if ( !na )
|
||||
{
|
||||
if ( !err || errno == EIO )
|
||||
{
|
||||
err = errno;
|
||||
if ( err != EIO )
|
||||
err = EBUSY;
|
||||
@ -956,10 +1031,13 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
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,
|
||||
ni->attr_list) != ni->attr_list_size) {
|
||||
if (!err || errno == EIO) {
|
||||
ni->attr_list ) != ni->attr_list_size )
|
||||
{
|
||||
if ( !err || errno == EIO )
|
||||
{
|
||||
err = errno;
|
||||
if ( err != EIO )
|
||||
err = EBUSY;
|
||||
@ -969,7 +1047,9 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
}
|
||||
NInoAttrListSetDirty( ni );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
err = EIO;
|
||||
ntfs_log_error( "Attribute list sync failed (bad size, "
|
||||
"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:
|
||||
/* Write this inode out to the $MFT (and $MFTMirr if applicable). */
|
||||
if (NInoTestAndClearDirty(ni)) {
|
||||
if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) {
|
||||
if (!err || errno == EIO) {
|
||||
if ( NInoTestAndClearDirty( ni ) )
|
||||
{
|
||||
if ( ntfs_mft_record_write( ni->vol, ni->mft_no, ni->mrec ) )
|
||||
{
|
||||
if ( !err || errno == EIO )
|
||||
{
|
||||
err = errno;
|
||||
if ( err != EIO )
|
||||
err = EBUSY;
|
||||
@ -994,10 +1077,12 @@ sync_inode:
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
for (i = 0; i < ni->nr_extents; ++i) {
|
||||
for ( i = 0; i < ni->nr_extents; ++i )
|
||||
{
|
||||
ntfs_inode *eni;
|
||||
|
||||
eni = ni->extent_nis[i];
|
||||
@ -1005,8 +1090,10 @@ sync_inode:
|
||||
continue;
|
||||
|
||||
if ( ntfs_mft_record_write( eni->vol, eni->mft_no,
|
||||
eni->mrec)) {
|
||||
if (!err || errno == EIO) {
|
||||
eni->mrec ) )
|
||||
{
|
||||
if ( !err || errno == EIO )
|
||||
{
|
||||
err = errno;
|
||||
if ( err != EIO )
|
||||
err = EBUSY;
|
||||
@ -1020,7 +1107,8 @@ sync_inode:
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if ( err )
|
||||
{
|
||||
errno = err;
|
||||
ret = -1;
|
||||
}
|
||||
@ -1043,10 +1131,12 @@ int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
int res;
|
||||
|
||||
res = ntfs_inode_sync_in_dir( ni, dir_ni );
|
||||
if (res) {
|
||||
if ( res )
|
||||
{
|
||||
if ( errno != EIO )
|
||||
errno = EBUSY;
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = ntfs_inode_close( ni );
|
||||
return ( res );
|
||||
}
|
||||
@ -1071,7 +1161,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
ATTR_LIST_ENTRY *ale = NULL;
|
||||
ntfs_attr *na;
|
||||
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
||||
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 );
|
||||
|
||||
if (NInoAttrList(ni) || ni->nr_extents) {
|
||||
if ( NInoAttrList( ni ) || ni->nr_extents )
|
||||
{
|
||||
errno = EEXIST;
|
||||
ntfs_log_perror( "Inode already has attribute list" );
|
||||
return -1;
|
||||
@ -1087,16 +1179,19 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
|
||||
/* Form attribute list. */
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if (!ctx) {
|
||||
if ( !ctx )
|
||||
{
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
if (ctx->attr->type == AT_ATTRIBUTE_LIST) {
|
||||
if ( ctx->attr->type == AT_ATTRIBUTE_LIST )
|
||||
{
|
||||
err = EIO;
|
||||
ntfs_log_perror( "Attribute list already present" );
|
||||
goto put_err_out;
|
||||
@ -1107,7 +1202,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
al_len += ale_size;
|
||||
|
||||
aln = realloc( al, al_len );
|
||||
if (!aln) {
|
||||
if ( !aln )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_perror( "Failed to realloc %d bytes", al_len );
|
||||
goto put_err_out;
|
||||
@ -1136,7 +1232,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
ale = ( ATTR_LIST_ENTRY * )( al + al_len );
|
||||
}
|
||||
/* Check for real error occurred. */
|
||||
if (errno != ENOENT) {
|
||||
if ( errno != ENOENT )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_perror( "%s: Attribute lookup failed, inode %lld",
|
||||
__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. */
|
||||
if ( le32_to_cpu( ni->mrec->bytes_allocated ) -
|
||||
le32_to_cpu( ni->mrec->bytes_in_use ) <
|
||||
offsetof(ATTR_RECORD, resident_end)) {
|
||||
offsetof( ATTR_RECORD, resident_end ) )
|
||||
{
|
||||
if ( ntfs_inode_free_space( ni,
|
||||
offsetof(ATTR_RECORD, resident_end))) {
|
||||
offsetof( ATTR_RECORD, resident_end ) ) )
|
||||
{
|
||||
/* Failed to free space. */
|
||||
err = errno;
|
||||
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. */
|
||||
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;
|
||||
ntfs_log_perror( "Couldn't add $ATTRIBUTE_LIST to MFT" );
|
||||
goto rollback;
|
||||
@ -1172,12 +1272,14 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
|
||||
/* Resize it. */
|
||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||
if (!na) {
|
||||
if ( !na )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_perror( "Failed to open just added $ATTRIBUTE_LIST" );
|
||||
goto remove_attrlist_record;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, al_len)) {
|
||||
if ( ntfs_attr_truncate( na, al_len ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_perror( "Failed to resize just added $ATTRIBUTE_LIST" );
|
||||
ntfs_attr_close( na );
|
||||
@ -1195,10 +1297,12 @@ remove_attrlist_record:
|
||||
/* Remove $ATTRIBUTE_LIST record. */
|
||||
ntfs_attr_reinit_search_ctx( ctx );
|
||||
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 ) )
|
||||
ntfs_log_perror( "Rollback failed to remove attrlist" );
|
||||
} else
|
||||
}
|
||||
else
|
||||
ntfs_log_perror( "Rollback failed to find attrlist" );
|
||||
/* Setup back in-memory runlist. */
|
||||
ni->attr_list = al;
|
||||
@ -1211,17 +1315,21 @@ rollback:
|
||||
*/
|
||||
ntfs_attr_reinit_search_ctx( ctx );
|
||||
ale = ( ATTR_LIST_ENTRY* )al;
|
||||
while ((u8*)ale < al + al_len) {
|
||||
if (MREF_LE(ale->mft_reference) != ni->mft_no) {
|
||||
while ( ( u8* )ale < al + al_len )
|
||||
{
|
||||
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
|
||||
{
|
||||
if ( !ntfs_attr_lookup( ale->type, ale->name,
|
||||
ale->name_length,
|
||||
CASE_SENSITIVE,
|
||||
sle64_to_cpu( ale->lowest_vcn ),
|
||||
NULL, 0, ctx)) {
|
||||
NULL, 0, ctx ) )
|
||||
{
|
||||
if ( ntfs_attr_record_move_to( ctx, ni ) )
|
||||
ntfs_log_perror( "Rollback failed to "
|
||||
"move attribute" );
|
||||
} else
|
||||
}
|
||||
else
|
||||
ntfs_log_perror( "Rollback failed to find attr" );
|
||||
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;
|
||||
int freed;
|
||||
|
||||
if (!ni || size < 0) {
|
||||
if ( !ni || size < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: ni=%p size=%d", __FUNCTION__, ni, size );
|
||||
return -1;
|
||||
@ -1277,13 +1386,15 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size)
|
||||
if ( ntfs_attr_position( AT_FILE_NAME, ctx ) )
|
||||
goto put_err_out;
|
||||
|
||||
while (1) {
|
||||
while ( 1 )
|
||||
{
|
||||
int record_size;
|
||||
/*
|
||||
* Check whether attribute is from different MFT record. If so,
|
||||
* 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:
|
||||
if ( ntfs_attr_position( AT_UNUSED, ctx ) )
|
||||
goto put_err_out;
|
||||
@ -1298,14 +1409,16 @@ retry:
|
||||
|
||||
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" );
|
||||
break;
|
||||
}
|
||||
freed += record_size;
|
||||
|
||||
/* Check whether we are done. */
|
||||
if (size <= freed) {
|
||||
if ( size <= freed )
|
||||
{
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
return 0;
|
||||
}
|
||||
@ -1339,7 +1452,8 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
|
||||
{
|
||||
ntfs_time now;
|
||||
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfs_log_error( "%s(): Invalid arguments.\n", __FUNCTION__ );
|
||||
return;
|
||||
}
|
||||
@ -1377,7 +1491,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
|
||||
int len, ret = 0;
|
||||
ntfschar *ustr;
|
||||
|
||||
if (!attr) {
|
||||
if ( !attr )
|
||||
{
|
||||
ntfs_log_error( "Invalid argument.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -1389,7 +1504,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
|
||||
if ( attr->type != AT_DATA )
|
||||
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" );
|
||||
return -1;
|
||||
}
|
||||
@ -1425,32 +1541,40 @@ int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size)
|
||||
|
||||
ret = 0;
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if (ctx) {
|
||||
if ( ctx )
|
||||
{
|
||||
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)",
|
||||
( long long )ni->mft_no );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
||||
le16_to_cpu( ctx->attr->value_offset ) );
|
||||
if (value && (size >= 8)) {
|
||||
if ( value && ( size >= 8 ) )
|
||||
{
|
||||
times = ( u64* )value;
|
||||
times[0] = le64_to_cpu( std_info->creation_time );
|
||||
ret = 8;
|
||||
if (size >= 16) {
|
||||
if ( size >= 16 )
|
||||
{
|
||||
times[1] = le64_to_cpu( std_info->last_data_change_time );
|
||||
ret = 16;
|
||||
}
|
||||
if (size >= 24) {
|
||||
if ( size >= 24 )
|
||||
{
|
||||
times[2] = le64_to_cpu( std_info->last_access_time );
|
||||
ret = 24;
|
||||
}
|
||||
if (size >= 32) {
|
||||
if ( size >= 32 )
|
||||
{
|
||||
times[3] = le64_to_cpu( std_info->last_mft_change_time );
|
||||
ret = 32;
|
||||
}
|
||||
} else
|
||||
if (!size)
|
||||
}
|
||||
else if ( !size )
|
||||
ret = 32;
|
||||
else
|
||||
ret = -ERANGE;
|
||||
@ -1486,18 +1610,23 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
||||
int ret;
|
||||
|
||||
ret = -1;
|
||||
if ((size >= 8) && !(flags & XATTR_CREATE)) {
|
||||
if ( ( size >= 8 ) && !( flags & XATTR_CREATE ) )
|
||||
{
|
||||
times = ( const u64* )value;
|
||||
now = ntfs_current_time();
|
||||
/* update the standard information attribute */
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if (ctx) {
|
||||
if ( ctx )
|
||||
{
|
||||
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION,
|
||||
AT_UNNAMED, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, ctx)) {
|
||||
0, NULL, 0, ctx ) )
|
||||
{
|
||||
ntfs_log_perror( "Failed to get standard info (inode %lld)",
|
||||
( long long )ni->mft_no );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
||||
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] );
|
||||
ni->creation_time
|
||||
= std_info->creation_time;
|
||||
if (size >= 16) {
|
||||
if ( size >= 16 )
|
||||
{
|
||||
std_info->last_data_change_time = cpu_to_le64( times[1] );
|
||||
ni->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] );
|
||||
ni->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;
|
||||
while ( !ntfs_attr_lookup( AT_FILE_NAME,
|
||||
AT_UNNAMED, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, ctx)) {
|
||||
0, NULL, 0, ctx ) )
|
||||
{
|
||||
fn = ( FILE_NAME_ATTR* )( ( u8 * )ctx->attr +
|
||||
le16_to_cpu( ctx->attr->value_offset ) );
|
||||
fn->creation_time
|
||||
@ -1548,15 +1680,16 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
||||
}
|
||||
if ( cnt )
|
||||
ret = 0;
|
||||
else {
|
||||
else
|
||||
{
|
||||
ntfs_log_perror( "Failed to get file names (inode %lld)",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
}
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
}
|
||||
} else
|
||||
if (size < 8)
|
||||
}
|
||||
else if ( size < 8 )
|
||||
errno = ERANGE;
|
||||
else
|
||||
errno = EEXIST;
|
||||
|
@ -40,7 +40,8 @@ typedef struct _ntfs_inode ntfs_inode;
|
||||
* Defined bits for the state field in the ntfs_inode structure.
|
||||
* (f) = files only, (d) = directories only
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||
|
||||
/* The NI_AttrList* tests only make sense for base inodes. */
|
||||
@ -103,7 +104,8 @@ typedef enum {
|
||||
* It is just used as an extension to the fields already provided in the VFS
|
||||
* inode.
|
||||
*/
|
||||
struct _ntfs_inode {
|
||||
struct _ntfs_inode
|
||||
{
|
||||
u64 mft_no; /* Inode / mft record number. */
|
||||
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
||||
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
||||
@ -122,7 +124,8 @@ struct _ntfs_inode {
|
||||
s32 nr_extents; /* For a base mft record, the number of
|
||||
attached extent inodes (0 if none), for
|
||||
extent records this is -1. */
|
||||
union { /* This union is only used if nr_extents != 0. */
|
||||
union /* This union is only used if nr_extents != 0. */
|
||||
{
|
||||
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
||||
ntfs inodes of the extent mft
|
||||
records belonging to this base
|
||||
@ -166,7 +169,8 @@ struct _ntfs_inode {
|
||||
le64 usn;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NTFS_UPDATE_ATIME = 1 << 0,
|
||||
NTFS_UPDATE_MTIME = 1 << 1,
|
||||
NTFS_UPDATE_CTIME = 1 << 2,
|
||||
|
@ -46,7 +46,8 @@
|
||||
/**
|
||||
* struct BIOS_PARAMETER_BLOCK - BIOS parameter block (bpb) structure.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u16 bytes_per_sector; /* Size of a sector in bytes. */
|
||||
u8 sectors_per_cluster; /* Size of a cluster in sectors. */
|
||||
u16 reserved_sectors; /* zero */
|
||||
@ -67,7 +68,8 @@ typedef struct {
|
||||
/**
|
||||
* struct NTFS_BOOT_SECTOR - NTFS boot sector structure.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 jump[3]; /* Irrelevant (jump to boot up code).*/
|
||||
u64 oem_id; /* Magic "NTFS ". */
|
||||
/*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
|
||||
* records (like mft records for example).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/* Found in $MFT/$DATA. */
|
||||
magic_FILE = const_cpu_to_le32( 0x454c4946 ), /* Mft entry. */
|
||||
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 +
|
||||
* (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
|
||||
record type and/or status. */
|
||||
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
|
||||
* 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
|
||||
contains the entries and bitmap attribute
|
||||
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
|
||||
* 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_IS_DIRECTORY = const_cpu_to_le16( 0x0002 ),
|
||||
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
|
||||
* other members of the attribute structure are present.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
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.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
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
|
||||
* choice of symbol... (-;
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
AT_UNUSED = const_cpu_to_le32( 0 ),
|
||||
AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10 ),
|
||||
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
|
||||
* equal then the second u32 values would be compared, etc.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
COLLATION_BINARY = const_cpu_to_le32( 0 ), /* Collate by binary
|
||||
compare where the first byte is most
|
||||
significant. */
|
||||
@ -573,7 +583,8 @@ typedef enum {
|
||||
* name attribute has this flag set and this is the only attribute indexed in
|
||||
* NT4.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ATTR_DEF_INDEXABLE = const_cpu_to_le32( 0x02 ), /* Attribute can be
|
||||
indexed. */
|
||||
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
|
||||
* actual bits are unknown.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*hex ofs*/
|
||||
/* 0*/ ntfschar name[0x40]; /* Unicode name of the attribute. Zero
|
||||
/* 0*/
|
||||
ntfschar name[0x40]; /* Unicode name of the attribute. Zero
|
||||
terminated. */
|
||||
/* 80*/ ATTR_TYPES type; /* Type of the attribute. */
|
||||
/* 84*/ u32 display_rule; /* Default display rule.
|
||||
@ -628,7 +641,8 @@ typedef struct {
|
||||
/**
|
||||
* enum ATTR_FLAGS - Attribute flags (16-bit).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ATTR_IS_COMPRESSED = const_cpu_to_le16( 0x0001 ),
|
||||
ATTR_COMPRESSION_MASK = const_cpu_to_le16( 0x00ff ), /* Compression
|
||||
method mask. Also, first
|
||||
@ -707,7 +721,8 @@ typedef enum {
|
||||
/**
|
||||
* 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
|
||||
(has implications for deleting and
|
||||
modifying the attribute). */
|
||||
@ -718,9 +733,11 @@ typedef enum {
|
||||
*
|
||||
* Always aligned to 8-byte boundary.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*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
|
||||
attribute (aligned to 8-byte boundary).
|
||||
Used to get to the next attribute. */
|
||||
@ -742,10 +759,13 @@ typedef struct {
|
||||
number is unique within this mft record (see
|
||||
MFT_RECORD/next_attribute_instance notes
|
||||
above for more details). */
|
||||
/* 16*/ union {
|
||||
/* 16*/ union
|
||||
{
|
||||
/* Resident attributes. */
|
||||
struct {
|
||||
/* 16 */ u32 value_length; /* Byte size of attribute value. */
|
||||
struct
|
||||
{
|
||||
/* 16 */
|
||||
u32 value_length; /* Byte size of attribute value. */
|
||||
/* 20 */ u16 value_offset; /* Byte offset of the attribute
|
||||
value from the start of the
|
||||
attribute record. When creating,
|
||||
@ -761,8 +781,10 @@ typedef struct {
|
||||
a resident attribute. */
|
||||
} __attribute__( ( __packed__ ) );
|
||||
/* Non-resident attributes. */
|
||||
struct {
|
||||
/* 16*/ VCN lowest_vcn; /* Lowest valid virtual cluster number
|
||||
struct
|
||||
{
|
||||
/* 16*/
|
||||
VCN lowest_vcn; /* Lowest valid virtual cluster number
|
||||
for this portion of the attribute value or
|
||||
0 if this is the only extent (usually the
|
||||
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).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/*
|
||||
* These flags are only present in the STANDARD_INFORMATION attribute
|
||||
* (in the field file_attributes).
|
||||
@ -905,9 +928,11 @@ typedef enum {
|
||||
* correct by practical experimentation on Windows NT4 SP6a and is hence
|
||||
* assumed to be the one and only correct interpretation.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*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(?). */
|
||||
/* 8*/ s64 last_data_change_time; /* Time the data attribute was last
|
||||
modified. */
|
||||
@ -922,16 +947,20 @@ typedef struct {
|
||||
last access times updates can be
|
||||
disabled altogether for speed. */
|
||||
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
|
||||
/* 36*/ union {
|
||||
/* 36*/ union
|
||||
{
|
||||
/* NTFS 1.2 (and previous, presumably) */
|
||||
struct {
|
||||
/* 36 */ u8 reserved12[12]; /* Reserved/alignment to 8-byte
|
||||
struct
|
||||
{
|
||||
/* 36 */
|
||||
u8 reserved12[12]; /* Reserved/alignment to 8-byte
|
||||
boundary. */
|
||||
/* 48 */ void *v1_end[0]; /* Marker for offsetof(). */
|
||||
} __attribute__( ( __packed__ ) );
|
||||
/* sizeof() = 48 bytes */
|
||||
/* NTFS 3.0 */
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
@ -951,7 +980,8 @@ typedef struct {
|
||||
* views that as a corruption, assuming that it behaves like this for all
|
||||
* attributes.
|
||||
*/
|
||||
/* 36*/ u32 maximum_versions; /* Maximum allowed versions for
|
||||
/* 36*/
|
||||
u32 maximum_versions; /* Maximum allowed versions for
|
||||
file. Zero if version numbering is disabled. */
|
||||
/* 40*/ u32 version_number; /* This file's version (if any).
|
||||
Set to zero if maximum_versions is zero. */
|
||||
@ -1016,9 +1046,11 @@ typedef struct {
|
||||
* NTFS 3.0 volumes).
|
||||
* - There are many named streams.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*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. */
|
||||
/* 6*/ u8 name_length; /* Size in Unicode chars of the name of the
|
||||
attribute or 0 if unnamed. */
|
||||
@ -1057,7 +1089,8 @@ typedef struct {
|
||||
* enum FILE_NAME_TYPE_FLAGS - Possible namespaces for filenames in ntfs.
|
||||
* (8-bit).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
FILE_NAME_POSIX = 0x00,
|
||||
/* This is the largest namespace. It is case sensitive 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
|
||||
* assumed to be the one and only correct interpretation.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*hex ofs*/
|
||||
/* 0*/ MFT_REF parent_directory; /* Directory this filename is
|
||||
/* 0*/
|
||||
MFT_REF parent_directory; /* Directory this filename is
|
||||
referenced from. */
|
||||
/* 8*/ s64 creation_time; /* Time file was created. */
|
||||
/* 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
|
||||
attribute. */
|
||||
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
|
||||
/* 3c*/ union {
|
||||
/* 3c*/ struct {
|
||||
/* 3c*/ u16 packed_ea_size; /* Size of the buffer needed to
|
||||
/* 3c*/ union
|
||||
{
|
||||
/* 3c*/
|
||||
struct
|
||||
{
|
||||
/* 3c*/
|
||||
u16 packed_ea_size; /* Size of the buffer needed to
|
||||
pack the extended attributes
|
||||
(EAs), if such are present.*/
|
||||
/* 3e*/ u16 reserved; /* Reserved for alignment. */
|
||||
@ -1146,7 +1185,8 @@ typedef struct {
|
||||
* Example of a GUID:
|
||||
* 1F010768-5A73-BC91-0010-A52216A7227B
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 data1; /* The first eight hexadecimal digits of the GUID. */
|
||||
u16 data2; /* The first 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).
|
||||
* domain_id - Reserved (always zero).
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
MFT_REF mft_reference; /* Mft record containing the object_id in
|
||||
the index entry key. */
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
GUID birth_volume_id;
|
||||
GUID birth_object_id;
|
||||
GUID domain_id;
|
||||
@ -1186,7 +1229,8 @@ typedef struct {
|
||||
*
|
||||
* NOTE: Always resident.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
GUID object_id; /* Unique id assigned to the
|
||||
file.*/
|
||||
/* 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
|
||||
to be found within the $Extend/$ObjId system file indexed under the
|
||||
above object_id. */
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
GUID birth_volume_id; /* Unique id of volume on which
|
||||
the file was first created.*/
|
||||
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 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_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 */
|
||||
@ -1237,7 +1284,8 @@ typedef enum { /* SID string prefix. */
|
||||
* made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and
|
||||
* the relative identifier SECURITY_CREATOR_OWNER_RID (0).
|
||||
*/
|
||||
typedef enum { /* Identifier authority. */
|
||||
typedef enum /* Identifier authority. */
|
||||
{
|
||||
SECURITY_NULL_RID = 0, /* S-1-0 */
|
||||
SECURITY_WORLD_RID = 0, /* S-1-1 */
|
||||
SECURITY_LOCAL_RID = 0, /* S-1-2 */
|
||||
@ -1349,8 +1397,10 @@ typedef enum { /* Identifier authority. */
|
||||
*
|
||||
* NOTE: This is stored as a big endian number.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 high_part; /* High 16-bits. */
|
||||
u32 low_part; /* Low 32-bits. */
|
||||
} __attribute__( ( __packed__ ) );
|
||||
@ -1385,7 +1435,8 @@ typedef union {
|
||||
* sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID
|
||||
* sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 revision;
|
||||
u8 sub_authority_count;
|
||||
SID_IDENTIFIER_AUTHORITY identifier_authority;
|
||||
@ -1395,7 +1446,8 @@ typedef struct {
|
||||
/**
|
||||
* enum SID_CONSTANTS - Current constants for SIDs.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
SID_REVISION = 1, /* Current revision level. */
|
||||
SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */
|
||||
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).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ACCESS_MIN_MS_ACE_TYPE = 0,
|
||||
ACCESS_ALLOWED_ACE_TYPE = 0,
|
||||
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
|
||||
* to indicate that a message is generated (in Windows!) for failed accesses.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/* The inheritance flags. */
|
||||
OBJECT_INHERIT_ACE = 0x01,
|
||||
CONTAINER_INHERIT_ACE = 0x02,
|
||||
@ -1467,7 +1521,8 @@ typedef enum {
|
||||
* which specifies the type and size of the ACE. The format of the subsequent
|
||||
* data depends on the ACE type.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ACE_TYPES type; /* Type of the ACE. */
|
||||
ACE_FLAGS flags; /* Flags describing the ACE. */
|
||||
u16 size; /* Size in bytes of the ACE. */
|
||||
@ -1478,7 +1533,8 @@ typedef struct {
|
||||
*
|
||||
* Defines the access rights.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/*
|
||||
* The specific rights (bits 0 to 15). Depend on the type of the
|
||||
* object being secured by the ACE.
|
||||
@ -1616,7 +1672,8 @@ typedef enum {
|
||||
*
|
||||
* FIXME: What exactly is this and what is it for? (AIA)
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ACCESS_MASK generic_read;
|
||||
ACCESS_MASK generic_write;
|
||||
ACCESS_MASK generic_execute;
|
||||
@ -1632,7 +1689,8 @@ typedef struct {
|
||||
*
|
||||
* 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. */
|
||||
ACE_TYPES type; /* Type of 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).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 1 ),
|
||||
ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 2 ),
|
||||
} OBJECT_ACE_FLAGS;
|
||||
@ -1654,7 +1713,8 @@ typedef enum {
|
||||
/**
|
||||
* struct ACCESS_ALLOWED_OBJECT_ACE -
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
ACE_TYPES type; /* Type of 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
|
||||
* are aligned on 4-byte boundaries.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 revision; /* Revision of this ACL. */
|
||||
u8 alignment1;
|
||||
u16 size; /* Allocated space in bytes for ACL. Includes this
|
||||
@ -1691,7 +1752,8 @@ typedef struct {
|
||||
/**
|
||||
* enum ACL_CONSTANTS - Current constants for ACLs.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/* Current revision. */
|
||||
ACL_REVISION = 2,
|
||||
ACL_REVISION_DS = 4,
|
||||
@ -1754,7 +1816,8 @@ typedef enum {
|
||||
* and all pointer fields are expressed as offsets from the
|
||||
* beginning of the security descriptor.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
SE_OWNER_DEFAULTED = const_cpu_to_le16( 0x0001 ),
|
||||
SE_GROUP_DEFAULTED = const_cpu_to_le16( 0x0002 ),
|
||||
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
|
||||
* as the sacl and dacl ACLs inside the security descriptor itself.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 revision; /* Revision level of the security descriptor. */
|
||||
u8 alignment;
|
||||
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
|
||||
@ -1809,7 +1873,8 @@ typedef struct {
|
||||
*
|
||||
* On disk, a self-relative security descriptor is used.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 revision; /* Revision level of the security descriptor. */
|
||||
u8 alignment;
|
||||
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
|
||||
@ -1835,7 +1900,8 @@ typedef struct {
|
||||
*
|
||||
* Current constants for security descriptors.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/* Current revision. */
|
||||
SECURITY_DESCRIPTOR_REVISION = 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 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 security_id; /* The security_id assigned to the descriptor. */
|
||||
u64 offset; /* Byte offset of this entry in the $SDS stream. */
|
||||
@ -1912,7 +1979,8 @@ typedef struct {
|
||||
/**
|
||||
* struct SDH_INDEX_DATA -
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 hash; /* Hash of the security descriptor. */
|
||||
u32 security_id; /* The security_id assigned to the descriptor. */
|
||||
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
|
||||
* $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
|
||||
unnamed structs. */
|
||||
u32 hash; /* Hash of the security descriptor. */
|
||||
@ -1955,7 +2024,8 @@ typedef struct {
|
||||
*
|
||||
* The collation type is COLLATION_NTOFS_ULONG.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 security_id; /* The security_id assigned to the descriptor. */
|
||||
} __attribute__( ( __packed__ ) ) SII_INDEX_KEY;
|
||||
|
||||
@ -1965,7 +2035,8 @@ typedef struct {
|
||||
* The keys are sorted first by hash and then by security_id.
|
||||
* The collation rule is COLLATION_NTOFS_SECURITY_HASH.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 hash; /* Hash of the security descriptor. */
|
||||
u32 security_id; /* The security_id assigned to the descriptor. */
|
||||
} __attribute__( ( __packed__ ) ) SDH_INDEX_KEY;
|
||||
@ -1976,14 +2047,16 @@ typedef struct {
|
||||
* NOTE: Always resident.
|
||||
* NOTE: Present only in FILE_Volume.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ntfschar name[0]; /* The name of the volume in Unicode. */
|
||||
} __attribute__( ( __packed__ ) ) VOLUME_NAME;
|
||||
|
||||
/**
|
||||
* enum VOLUME_FLAGS - Possible flags for the volume (16-bit).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
VOLUME_IS_DIRTY = const_cpu_to_le16( 0x0001 ),
|
||||
VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16( 0x0002 ),
|
||||
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
|
||||
* NTFS 1.2. I haven't personally seen other values yet.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u64 reserved; /* Not used (yet?). */
|
||||
u8 major_ver; /* Major 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.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 data[0]; /* The file's data contents. */
|
||||
} __attribute__( ( __packed__ ) ) DATA_ATTR;
|
||||
|
||||
/**
|
||||
* enum INDEX_HEADER_FLAGS - Index header flags (8-bit).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/* When index header is in an index root attribute: */
|
||||
SMALL_INDEX = 0, /* The index is small enough to fit inside the
|
||||
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
|
||||
* start of the index root or index allocation structures themselves.
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0*/ u32 entries_offset; /* Byte offset from the INDEX_HEADER to first
|
||||
typedef struct
|
||||
{
|
||||
/* 0*/
|
||||
u32 entries_offset; /* Byte offset from the INDEX_HEADER to first
|
||||
INDEX_ENTRY, aligned to 8-byte boundary. */
|
||||
/* 4*/ u32 index_length; /* Data size in byte of the INDEX_ENTRY's,
|
||||
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
|
||||
* directories do not contain entries for themselves, though.
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0*/ ATTR_TYPES type; /* Type of the indexed attribute. Is
|
||||
typedef struct
|
||||
{
|
||||
/* 0*/
|
||||
ATTR_TYPES type; /* Type of the indexed attribute. Is
|
||||
$FILE_NAME for directories, zero
|
||||
for view indexes. No other values
|
||||
allowed. */
|
||||
@ -2123,7 +2203,8 @@ typedef struct {
|
||||
* INDEX_BLOCK structure containing an index header, followed by a sequence of
|
||||
* 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. */
|
||||
NTFS_RECORD_TYPES magic;/* Magic is "INDX". */
|
||||
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
|
||||
* primary key / is not a key at all. (AIA)
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 reparse_tag; /* Reparse point type (inc. flags). */
|
||||
MFT_REF file_id; /* Mft record of the file containing the
|
||||
reparse point attribute. */
|
||||
@ -2167,7 +2249,8 @@ typedef struct {
|
||||
/**
|
||||
* enum QUOTA_FLAGS - Quota flags (32-bit).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
/* The user quota flags. Names explain meaning. */
|
||||
QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32( 0x00000001 ),
|
||||
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.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 version; /* Currently equals 2. */
|
||||
QUOTA_FLAGS flags; /* Flags describing this quota entry. */
|
||||
u64 bytes_used; /* How many bytes of the quota are in use. */
|
||||
@ -2233,7 +2317,8 @@ typedef struct {
|
||||
/**
|
||||
* struct QUOTA_O_INDEX_DATA -
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 owner_id;
|
||||
u32 unknown; /* Always 32. Seems to be padding and it's not
|
||||
counted in the INDEX_ENTRY's data_length.
|
||||
@ -2243,7 +2328,8 @@ typedef struct {
|
||||
/**
|
||||
* enum PREDEFINED_OWNER_IDS - Predefined owner_id values (32-bit).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
QUOTA_INVALID_ID = const_cpu_to_le32( 0x00000000 ),
|
||||
QUOTA_DEFAULTS_ID = const_cpu_to_le32( 0x00000001 ),
|
||||
QUOTA_FIRST_USER_ID = const_cpu_to_le32( 0x00000100 ),
|
||||
@ -2252,7 +2338,8 @@ typedef enum {
|
||||
/**
|
||||
* 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
|
||||
sub-node, i.e. a reference to an index
|
||||
block in form of a virtual cluster
|
||||
@ -2271,10 +2358,14 @@ typedef enum {
|
||||
* !!!!! SEE DESCRIPTION OF THE FIELDS AT INDEX_ENTRY !!!!!
|
||||
* ==========================================================
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0*/ union {
|
||||
typedef struct
|
||||
{
|
||||
/* 0*/
|
||||
union
|
||||
{
|
||||
MFT_REF indexed_file;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
u16 data_offset;
|
||||
u16 data_length;
|
||||
u32 reservedV;
|
||||
@ -2296,14 +2387,17 @@ typedef struct {
|
||||
*
|
||||
* 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. */
|
||||
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
|
||||
described by this index
|
||||
entry. Used for directory
|
||||
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
|
||||
INDEX_ENTRY. Follows the
|
||||
index key. */
|
||||
@ -2320,7 +2414,8 @@ typedef struct {
|
||||
/* 12*/ INDEX_ENTRY_FLAGS ie_flags; /* Bit field of INDEX_ENTRY_* flags. */
|
||||
/* 14*/ u16 reserved; /* Reserved/align to 8-byte boundary. */
|
||||
/* 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
|
||||
NTFS versions before 3.0 the only valid key is the
|
||||
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
|
||||
* number of clusters in the index allocation attribute.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 bitmap[0]; /* Array of bits. */
|
||||
} __attribute__( ( __packed__ ) ) BITMAP_ATTR;
|
||||
|
||||
@ -2388,7 +2484,8 @@ typedef struct {
|
||||
* bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
|
||||
* 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_HIGH_LATENCY = const_cpu_to_le32( 0x40000000 ),
|
||||
IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32( 0x80000000 ),
|
||||
@ -2416,7 +2513,8 @@ typedef enum {
|
||||
*
|
||||
* NOTE: Can be resident or non-resident.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 reparse_tag; /* Reparse point type (inc. flags). */
|
||||
u16 reparse_data_length; /* Byte size of reparse data. */
|
||||
u16 reserved; /* Align to 8-byte boundary. */
|
||||
@ -2428,7 +2526,8 @@ typedef struct {
|
||||
*
|
||||
* NOTE: Always resident.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u16 ea_length; /* Byte size of the packed extended
|
||||
attributes. */
|
||||
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).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NEED_EA = 0x80, /* Indicate that the file to which the EA
|
||||
belongs cannot be interpreted without
|
||||
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 seems that name is always uppercased. Is it true?
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 next_entry_offset; /* Offset to the next EA_ATTR. */
|
||||
EA_FLAGS flags; /* Flags describing the EA. */
|
||||
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
|
||||
* NTFS 3.0 during beta testing.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/* Irrelevant as feature unused. */
|
||||
} __attribute__( ( __packed__ ) ) PROPERTY_SET;
|
||||
|
||||
@ -2491,7 +2593,8 @@ typedef struct {
|
||||
* Used by the Encrypting File System (EFS). All encrypted files have this
|
||||
* attribute with the name $EFS. See below for the relevant structures.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/* Can be anything the creator chooses. */
|
||||
} __attribute__( ( __packed__ ) ) LOGGED_UTILITY_STREAM;
|
||||
|
||||
@ -2527,8 +2630,10 @@ typedef struct {
|
||||
*
|
||||
* The header of the Logged utility stream (0x100) attribute named "$EFS".
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0*/ u32 length; /* Length of EFS attribute in bytes. */
|
||||
typedef struct
|
||||
{
|
||||
/* 0*/
|
||||
u32 length; /* Length of EFS attribute in bytes. */
|
||||
u32 state; /* Always 0? */
|
||||
u32 version; /* Efs version. Always 2? */
|
||||
u32 crypto_api_version; /* Always 0? */
|
||||
@ -2551,7 +2656,8 @@ typedef struct {
|
||||
/**
|
||||
* struct EFS_DF_ARRAY_HEADER -
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 df_count; /* Number of data decryption/recovery fields in
|
||||
the array. */
|
||||
} __attribute__( ( __packed__ ) ) EFS_DF_ARRAY_HEADER;
|
||||
@ -2559,8 +2665,10 @@ typedef struct {
|
||||
/**
|
||||
* struct EFS_DF_HEADER -
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0*/ u32 df_length; /* Length of this data decryption/recovery
|
||||
typedef struct
|
||||
{
|
||||
/* 0*/
|
||||
u32 df_length; /* Length of this data decryption/recovery
|
||||
field in bytes. */
|
||||
u32 cred_header_offset; /* Offset in bytes to the credential header. */
|
||||
u32 fek_size; /* Size in bytes of the encrypted file
|
||||
@ -2573,8 +2681,10 @@ typedef struct {
|
||||
/**
|
||||
* struct EFS_DF_CREDENTIAL_HEADER -
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0*/ u32 cred_length; /* Length of this credential in bytes. */
|
||||
typedef struct
|
||||
{
|
||||
/* 0*/
|
||||
u32 cred_length; /* Length of this credential in bytes. */
|
||||
u32 sid_offset; /* Offset in bytes to the user's sid from start
|
||||
of this structure. Zero if no sid is
|
||||
present. */
|
||||
@ -2583,10 +2693,13 @@ typedef struct {
|
||||
2 = Unexpected type.
|
||||
3 = Certificate thumbprint.
|
||||
other = Unknown type. */
|
||||
union {
|
||||
union
|
||||
{
|
||||
/* CryptoAPI container. */
|
||||
struct {
|
||||
/* 12*/ u32 container_name_offset; /* Offset in bytes to
|
||||
struct
|
||||
{
|
||||
/* 12*/
|
||||
u32 container_name_offset; /* Offset in bytes to
|
||||
the name of the container from start of this
|
||||
structure (may not be zero). */
|
||||
/* 16*/ u32 provider_name_offset; /* Offset in bytes to
|
||||
@ -2599,8 +2712,10 @@ typedef struct {
|
||||
public key blob. */
|
||||
} __attribute__( ( __packed__ ) );
|
||||
/* Certificate thumbprint. */
|
||||
struct {
|
||||
/* 12*/ u32 cert_thumbprint_header_size; /* Size in
|
||||
struct
|
||||
{
|
||||
/* 12*/
|
||||
u32 cert_thumbprint_header_size; /* Size in
|
||||
bytes of the header of the certificate
|
||||
thumbprint. */
|
||||
/* 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 -
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0*/ u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */
|
||||
typedef struct
|
||||
{
|
||||
/* 0*/
|
||||
u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */
|
||||
u32 thumbprint_size; /* Size of thumbprint in bytes. */
|
||||
/* 8*/ u32 container_name_offset; /* Offset in bytes to the name of the
|
||||
container from start of this
|
||||
@ -2635,7 +2752,8 @@ typedef struct {
|
||||
|
||||
typedef EFS_DF_CERTIFICATE_THUMBPRINT_HEADER EFS_DF_CERT_THUMBPRINT_HEADER;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
INTX_SYMBOLIC_LINK =
|
||||
const_cpu_to_le64( 0x014B4E4C78746E49ULL ), /* "IntxLNK\1" */
|
||||
INTX_CHARACTER_DEVICE =
|
||||
@ -2644,11 +2762,14 @@ typedef enum {
|
||||
const_cpu_to_le64( 0x004B4C4278746E49ULL ), /* "IntxBLK\0" */
|
||||
} INTX_FILE_TYPES;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
INTX_FILE_TYPES magic; /* Intx file magic. */
|
||||
union {
|
||||
union
|
||||
{
|
||||
/* For character and block devices. */
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
u64 major; /* Major device number. */
|
||||
u64 minor; /* Minor device number. */
|
||||
void *device_end[0]; /* Marker for offsetof(). */
|
||||
|
@ -55,7 +55,8 @@
|
||||
#define NTFS_LCNALLOC_BSIZE 4096
|
||||
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
ZONE_MFT = 1,
|
||||
ZONE_DATA1 = 2,
|
||||
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 )
|
||||
{
|
||||
if (lcn >= vol->mft_zone_end) {
|
||||
if (vol->full_zones & ZONE_DATA1) {
|
||||
if ( lcn >= vol->mft_zone_end )
|
||||
{
|
||||
if ( vol->full_zones & ZONE_DATA1 )
|
||||
{
|
||||
ntfs_cluster_update_zone_pos( vol, ZONE_DATA1, lcn );
|
||||
vol->full_zones &= ~ZONE_DATA1;
|
||||
}
|
||||
} else
|
||||
if (lcn < vol->mft_zone_start) {
|
||||
if (vol->full_zones & ZONE_DATA2) {
|
||||
}
|
||||
else if ( lcn < vol->mft_zone_start )
|
||||
{
|
||||
if ( vol->full_zones & ZONE_DATA2 )
|
||||
{
|
||||
ntfs_cluster_update_zone_pos( vol, ZONE_DATA2, lcn );
|
||||
vol->full_zones &= ~ZONE_DATA2;
|
||||
}
|
||||
} else {
|
||||
if (vol->full_zones & ZONE_MFT) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( vol->full_zones & ZONE_MFT )
|
||||
{
|
||||
ntfs_cluster_update_zone_pos( vol, ZONE_MFT, lcn );
|
||||
vol->full_zones &= ~ZONE_MFT;
|
||||
}
|
||||
@ -122,38 +130,49 @@ static s64 max_empty_bit_range(unsigned char *buf, int size)
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
|
||||
i = 0;
|
||||
while (i < size) {
|
||||
switch (*buf) {
|
||||
while ( i < size )
|
||||
{
|
||||
switch ( *buf )
|
||||
{
|
||||
case 0 :
|
||||
do {
|
||||
do
|
||||
{
|
||||
buf++;
|
||||
run += 8;
|
||||
i++;
|
||||
} while ((i < size) && !*buf);
|
||||
}
|
||||
while ( ( i < size ) && !*buf );
|
||||
break;
|
||||
case 255 :
|
||||
if (run > max_range) {
|
||||
if ( run > max_range )
|
||||
{
|
||||
max_range = run;
|
||||
start_pos = ( s64 )i * 8 - run;
|
||||
}
|
||||
run = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
buf++;
|
||||
i++;
|
||||
} while ((i < size) && (*buf == 255));
|
||||
}
|
||||
while ( ( i < size ) && ( *buf == 255 ) );
|
||||
break;
|
||||
default :
|
||||
for (j = 0; j < 8; j++) {
|
||||
for ( j = 0; j < 8; j++ )
|
||||
{
|
||||
|
||||
int bit = *buf & ( 1 << j );
|
||||
|
||||
if (bit) {
|
||||
if (run > max_range) {
|
||||
if ( bit )
|
||||
{
|
||||
if ( run > max_range )
|
||||
{
|
||||
max_range = run;
|
||||
start_pos = ( s64 )i * 8 + ( j - run );
|
||||
}
|
||||
run = 0;
|
||||
} else
|
||||
}
|
||||
else
|
||||
run++;
|
||||
}
|
||||
i++;
|
||||
@ -181,7 +200,8 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
|
||||
*writeback = 0;
|
||||
|
||||
written = ntfs_attr_pwrite( vol->lcnbmp_na, pos, size, b );
|
||||
if (written != size) {
|
||||
if ( written != size )
|
||||
{
|
||||
if ( !written )
|
||||
errno = EIO;
|
||||
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" );
|
||||
|
||||
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;
|
||||
ntfs_log_perror( "%s: vcn: %lld, count: %lld, lcn: %lld",
|
||||
__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 */
|
||||
if (!count) {
|
||||
if ( !count )
|
||||
{
|
||||
rl = ntfs_malloc( 0x1000 );
|
||||
if (rl) {
|
||||
if ( rl )
|
||||
{
|
||||
rl[0].vcn = start_vcn;
|
||||
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[0].length = 0;
|
||||
@ -282,7 +305,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
has_guess = 1;
|
||||
zone_start = start_lcn;
|
||||
|
||||
if (zone_start < 0) {
|
||||
if ( zone_start < 0 )
|
||||
{
|
||||
if ( zone == DATA_ZONE )
|
||||
zone_start = vol->data1_zone_pos;
|
||||
else
|
||||
@ -296,13 +320,18 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
zone_start == vol->mft_zone_end )
|
||||
pass = 2;
|
||||
|
||||
if (zone_start < vol->mft_zone_start) {
|
||||
if ( zone_start < vol->mft_zone_start )
|
||||
{
|
||||
zone_end = vol->mft_zone_start;
|
||||
search_zone = ZONE_DATA2;
|
||||
} else if (zone_start < vol->mft_zone_end) {
|
||||
}
|
||||
else if ( zone_start < vol->mft_zone_end )
|
||||
{
|
||||
zone_end = vol->mft_zone_end;
|
||||
search_zone = ZONE_MFT;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
zone_end = vol->nr_clusters;
|
||||
search_zone = ZONE_DATA1;
|
||||
}
|
||||
@ -312,14 +341,16 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
/* Loop until all clusters are allocated. */
|
||||
clusters = count;
|
||||
rlpos = rlsize = 0;
|
||||
while (1) {
|
||||
while ( 1 )
|
||||
{
|
||||
/* check whether we have exhausted the current zone */
|
||||
if ( search_zone & vol->full_zones )
|
||||
goto zone_pass_done;
|
||||
last_read_pos = bmp_pos >> 3;
|
||||
br = ntfs_attr_pread( vol->lcnbmp_na, last_read_pos,
|
||||
NTFS_LCNALLOC_BSIZE, buf );
|
||||
if (br <= 0) {
|
||||
if ( br <= 0 )
|
||||
{
|
||||
if ( !br )
|
||||
goto zone_pass_done;
|
||||
err = errno;
|
||||
@ -335,15 +366,20 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
bmp_pos &= ~7;
|
||||
writeback = 0;
|
||||
|
||||
while (lcn < buf_size) {
|
||||
while ( lcn < buf_size )
|
||||
{
|
||||
byte = buf + ( lcn >> 3 );
|
||||
bit = 1 << ( lcn & 7 );
|
||||
if (has_guess) {
|
||||
if (*byte & bit) {
|
||||
if ( has_guess )
|
||||
{
|
||||
if ( *byte & bit )
|
||||
{
|
||||
has_guess = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
lcn = max_empty_bit_range( buf, br );
|
||||
if ( lcn < 0 )
|
||||
break;
|
||||
@ -354,10 +390,12 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
/* First free bit is at lcn + bmp_pos. */
|
||||
|
||||
/* Reallocate memory if necessary. */
|
||||
if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
|
||||
if ( ( rlpos + 2 ) * ( int )sizeof( runlist ) >= rlsize )
|
||||
{
|
||||
rlsize += 4096;
|
||||
trl = realloc( rl, rlsize );
|
||||
if (!trl) {
|
||||
if ( !trl )
|
||||
{
|
||||
err = ENOMEM;
|
||||
ntfs_log_perror( "realloc() failed" );
|
||||
goto wb_err_ret;
|
||||
@ -379,7 +417,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
* Coalesce with previous run if adjacent LCNs.
|
||||
* Otherwise, append a new run.
|
||||
*/
|
||||
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
|
||||
if ( prev_lcn == lcn + bmp_pos - prev_run_len && rlpos )
|
||||
{
|
||||
ntfs_log_debug( "Cluster coalesce: prev_lcn: "
|
||||
"%lld lcn: %lld bmp_pos: %lld "
|
||||
"prev_run_len: %lld\n",
|
||||
@ -387,11 +426,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
( long long )lcn, ( long long )bmp_pos,
|
||||
( long long )prev_run_len );
|
||||
rl[rlpos - 1].length = ++prev_run_len;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rlpos )
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
||||
prev_run_len;
|
||||
else {
|
||||
else
|
||||
{
|
||||
rl[rlpos].vcn = start_vcn;
|
||||
ntfs_log_debug( "Start_vcn: %lld\n",
|
||||
( 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].length );
|
||||
/* Done? */
|
||||
if (!--clusters) {
|
||||
if ( !--clusters )
|
||||
{
|
||||
if ( used_zone_pos )
|
||||
ntfs_cluster_update_zone_pos( vol,
|
||||
search_zone, lcn + bmp_pos + 1 +
|
||||
@ -418,12 +461,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
lcn++;
|
||||
}
|
||||
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||
if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
|
||||
{
|
||||
err = errno;
|
||||
goto err_ret;
|
||||
}
|
||||
|
||||
if (!used_zone_pos) {
|
||||
if ( !used_zone_pos )
|
||||
{
|
||||
|
||||
used_zone_pos = 1;
|
||||
|
||||
@ -438,7 +483,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
zone_start == vol->mft_zone_end )
|
||||
pass = 2;
|
||||
bmp_pos = zone_start;
|
||||
} else
|
||||
}
|
||||
else
|
||||
bmp_pos += buf_size;
|
||||
|
||||
if ( bmp_pos < zone_end )
|
||||
@ -446,7 +492,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
|
||||
zone_pass_done:
|
||||
ntfs_log_trace( "Finished current zone pass(%i).\n", pass );
|
||||
if (pass == 1) {
|
||||
if ( pass == 1 )
|
||||
{
|
||||
pass = 2;
|
||||
zone_end = zone_start;
|
||||
|
||||
@ -469,10 +516,12 @@ zone_pass_done:
|
||||
done_zones_check:
|
||||
done_zones |= search_zone;
|
||||
vol->full_zones |= search_zone;
|
||||
if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2)) {
|
||||
if ( done_zones < ( ZONE_MFT + ZONE_DATA1 + ZONE_DATA2 ) )
|
||||
{
|
||||
ntfs_log_trace( "Switching zone.\n" );
|
||||
pass = 1;
|
||||
if (rlpos) {
|
||||
if ( rlpos )
|
||||
{
|
||||
LCN tc = rl[rlpos - 1].lcn +
|
||||
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
||||
|
||||
@ -481,7 +530,8 @@ done_zones_check:
|
||||
search_zone, tc );
|
||||
}
|
||||
|
||||
switch (search_zone) {
|
||||
switch ( search_zone )
|
||||
{
|
||||
case ZONE_MFT:
|
||||
ntfs_log_trace( "Zone switch: mft -> data1\n" );
|
||||
switch_to_data1_zone: search_zone = ZONE_DATA1;
|
||||
@ -499,7 +549,8 @@ switch_to_data1_zone: search_zone = ZONE_DATA1;
|
||||
pass = 2;
|
||||
break;
|
||||
case ZONE_DATA2:
|
||||
if (!(done_zones & ZONE_DATA1)) {
|
||||
if ( !( done_zones & ZONE_DATA1 ) )
|
||||
{
|
||||
ntfs_log_trace( "data2 -> data1\n" );
|
||||
goto switch_to_data1_zone;
|
||||
}
|
||||
@ -514,7 +565,8 @@ switch_to_data1_zone: search_zone = ZONE_DATA1;
|
||||
|
||||
bmp_pos = zone_start;
|
||||
|
||||
if (zone_start == zone_end) {
|
||||
if ( zone_start == zone_end )
|
||||
{
|
||||
ntfs_log_trace( "Empty zone, skipped.\n" );
|
||||
goto done_zones_check;
|
||||
}
|
||||
@ -532,13 +584,15 @@ done_ret:
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[rlpos].length = 0;
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||
if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
|
||||
{
|
||||
err = errno;
|
||||
goto err_ret;
|
||||
}
|
||||
done_err_ret:
|
||||
free( buf );
|
||||
if (err) {
|
||||
if ( err )
|
||||
{
|
||||
errno = err;
|
||||
ntfs_log_perror( "Failed to allocate clusters" );
|
||||
rl = NULL;
|
||||
@ -553,7 +607,8 @@ wb_err_ret:
|
||||
err = errno;
|
||||
err_ret:
|
||||
ntfs_log_trace( "At err_ret.\n" );
|
||||
if (rl) {
|
||||
if ( rl )
|
||||
{
|
||||
/* Add runlist terminator element. */
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
@ -580,15 +635,18 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
|
||||
for (; rl->length; rl++) {
|
||||
for ( ; rl->length; rl++ )
|
||||
{
|
||||
|
||||
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||
( long long )rl->lcn, ( long long )rl->length );
|
||||
|
||||
if (rl->lcn >= 0) {
|
||||
if ( rl->lcn >= 0 )
|
||||
{
|
||||
update_full_status( vol, rl->lcn );
|
||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
||||
rl->length)) {
|
||||
rl->length ) )
|
||||
{
|
||||
ntfs_log_perror( "Cluster deallocation failed "
|
||||
"(%lld, %lld)",
|
||||
( 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",
|
||||
( long long )lcn, ( long long )count );
|
||||
|
||||
if (lcn >= 0) {
|
||||
if ( lcn >= 0 )
|
||||
{
|
||||
update_full_status( vol, lcn );
|
||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, lcn,
|
||||
count)) {
|
||||
count ) )
|
||||
{
|
||||
ntfs_log_perror( "Cluster deallocation failed "
|
||||
"(%lld, %lld)",
|
||||
( 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;
|
||||
|
||||
if ( !vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
|
||||
(count < 0 && count != -1)) {
|
||||
( count < 0 && count != -1 ) )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments!\n" );
|
||||
errno = EINVAL;
|
||||
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 );
|
||||
|
||||
rl = ntfs_attr_find_vcn( na, start_vcn );
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
if ( errno == ENOENT )
|
||||
ret = 0;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
if ( rl->lcn < 0 && rl->lcn != LCN_HOLE )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "%s: Unexpected lcn (%lld)", __FUNCTION__,
|
||||
( long long )rl->lcn );
|
||||
@ -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 )
|
||||
to_free = count;
|
||||
|
||||
if (rl->lcn != LCN_HOLE) {
|
||||
if ( rl->lcn != LCN_HOLE )
|
||||
{
|
||||
/* Do the actual freeing of the clusters in this run. */
|
||||
update_full_status( vol, rl->lcn + delta );
|
||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn + delta,
|
||||
@ -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
|
||||
* free them.
|
||||
*/
|
||||
for (; rl->length && count != 0; ++rl) {
|
||||
for ( ; rl->length && count != 0; ++rl )
|
||||
{
|
||||
// FIXME: Need to try ntfs_attr_map_runlist() for attribute
|
||||
// list support! (AIA)
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
if ( rl->lcn < 0 && rl->lcn != LCN_HOLE )
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "%s: Invalid lcn (%lli)",
|
||||
@ -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 )
|
||||
to_free = count;
|
||||
|
||||
if (rl->lcn != LCN_HOLE) {
|
||||
if ( rl->lcn != LCN_HOLE )
|
||||
{
|
||||
update_full_status( vol, rl->lcn );
|
||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
||||
to_free)) {
|
||||
to_free ) )
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_perror( "%s: Clearing bitmap run failed",
|
||||
__FUNCTION__ );
|
||||
@ -750,7 +818,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
count -= to_free;
|
||||
}
|
||||
|
||||
if (count != -1 && count != 0) {
|
||||
if ( count != -1 && count != 0 )
|
||||
{
|
||||
// FIXME: Eeek! BUG()
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "%s: count still not zero (%lld)", __FUNCTION__,
|
||||
|
@ -31,7 +31,8 @@
|
||||
/**
|
||||
* enum NTFS_CLUSTER_ALLOCATION_ZONES -
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
FIRST_ZONE = 0, /* For sanity checking. */
|
||||
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
||||
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
||||
|
@ -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_system_page_size &
|
||||
( 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" );
|
||||
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
|
||||
* size (2nd restart page).
|
||||
*/
|
||||
if (pos && pos != logfile_system_page_size) {
|
||||
if ( pos && pos != logfile_system_page_size )
|
||||
{
|
||||
ntfs_log_error( "Found restart area in incorrect "
|
||||
"position in $LogFile.\n" );
|
||||
return FALSE;
|
||||
}
|
||||
/* We only know how to handle version 1.1. */
|
||||
if ( sle16_to_cpu( rp->major_ver ) != 1 ||
|
||||
sle16_to_cpu(rp->minor_ver) != 1) {
|
||||
sle16_to_cpu( rp->minor_ver ) != 1 )
|
||||
{
|
||||
ntfs_log_error( "$LogFile version %i.%i is not "
|
||||
"supported. (This driver supports version "
|
||||
"1.1 only.)\n", ( int )sle16_to_cpu( rp->major_ver ),
|
||||
@ -97,13 +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
|
||||
* update sequence array.
|
||||
*/
|
||||
if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
|
||||
if ( ntfs_is_chkd_record( rp->magic ) && !le16_to_cpu( rp->usa_count ) )
|
||||
{
|
||||
have_usa = FALSE;
|
||||
goto skip_usa_checks;
|
||||
}
|
||||
/* Verify the size of the update sequence array. */
|
||||
usa_count = 1 + ( logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS );
|
||||
if (usa_count != le16_to_cpu(rp->usa_count)) {
|
||||
if ( usa_count != le16_to_cpu( rp->usa_count ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart page specifies "
|
||||
"inconsistent update sequence array count.\n" );
|
||||
return FALSE;
|
||||
@ -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_end = usa_ofs + usa_count * sizeof( u16 );
|
||||
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 "
|
||||
"inconsistent update sequence array offset.\n" );
|
||||
return FALSE;
|
||||
@ -127,7 +133,8 @@ skip_usa_checks:
|
||||
ra_ofs = le16_to_cpu( rp->restart_area_offset );
|
||||
if ( ra_ofs & 7 || ( have_usa ? ra_ofs < usa_end :
|
||||
ra_ofs < sizeof( RESTART_PAGE_HEADER ) ) ||
|
||||
ra_ofs > logfile_system_page_size) {
|
||||
ra_ofs > logfile_system_page_size )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart page specifies "
|
||||
"inconsistent restart area offset.\n" );
|
||||
return FALSE;
|
||||
@ -136,7 +143,8 @@ skip_usa_checks:
|
||||
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
|
||||
* set.
|
||||
*/
|
||||
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
|
||||
if ( !ntfs_is_chkd_record( rp->magic ) && sle64_to_cpu( rp->chkdsk_lsn ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart page is not modified "
|
||||
"by chkdsk but a chkdsk LSN is specified.\n" );
|
||||
return FALSE;
|
||||
@ -174,7 +182,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
* safe to access ra->client_array_offset.
|
||||
*/
|
||||
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 "
|
||||
"inconsistent file offset.\n" );
|
||||
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 );
|
||||
if ( ( ( ca_ofs + 7 ) & ~7 ) != ca_ofs ||
|
||||
ra_ofs + ca_ofs > ( u16 )( NTFS_BLOCK_SIZE -
|
||||
sizeof(u16))) {
|
||||
sizeof( u16 ) ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart area specifies "
|
||||
"inconsistent client array offset.\n" );
|
||||
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 ) ||
|
||||
( u32 )( ra_ofs + le16_to_cpu( ra->restart_area_length ) ) >
|
||||
le32_to_cpu( rp->system_page_size ) ||
|
||||
ra_len > le16_to_cpu(ra->restart_area_length)) {
|
||||
ra_len > le16_to_cpu( ra->restart_area_length ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart area is out of bounds "
|
||||
"of the system page size specified by the "
|
||||
"restart page header and/or the specified "
|
||||
@ -221,7 +232,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
le16_to_cpu( ra->log_clients ) ) ||
|
||||
( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||
le16_to_cpu( ra->client_in_use_list ) >=
|
||||
le16_to_cpu(ra->log_clients))) {
|
||||
le16_to_cpu( ra->log_clients ) ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart area specifies "
|
||||
"overflowing client free and/or in use lists.\n" );
|
||||
return FALSE;
|
||||
@ -232,25 +244,29 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
*/
|
||||
file_size = ( u64 )sle64_to_cpu( ra->file_size );
|
||||
fs_bits = 0;
|
||||
while (file_size) {
|
||||
while ( file_size )
|
||||
{
|
||||
file_size >>= 1;
|
||||
fs_bits++;
|
||||
}
|
||||
if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) {
|
||||
if ( le32_to_cpu( ra->seq_number_bits ) != ( u32 )( 67 - fs_bits ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart area specifies "
|
||||
"inconsistent sequence number bits.\n" );
|
||||
return FALSE;
|
||||
}
|
||||
/* The log record header length must be a multiple of 8. */
|
||||
if ( ( ( le16_to_cpu( ra->log_record_header_length ) + 7 ) & ~7 ) !=
|
||||
le16_to_cpu(ra->log_record_header_length)) {
|
||||
le16_to_cpu( ra->log_record_header_length ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart area specifies "
|
||||
"inconsistent log record header length.\n" );
|
||||
return FALSE;
|
||||
}
|
||||
/* Ditto for the log page data offset. */
|
||||
if ( ( ( le16_to_cpu( ra->log_page_data_offset ) + 7 ) & ~7 ) !=
|
||||
le16_to_cpu(ra->log_page_data_offset)) {
|
||||
le16_to_cpu( ra->log_page_data_offset ) )
|
||||
{
|
||||
ntfs_log_error( "$LogFile restart area specifies "
|
||||
"inconsistent log page data offset.\n" );
|
||||
return FALSE;
|
||||
@ -297,20 +313,23 @@ static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
|
||||
in_free_list = TRUE;
|
||||
check_list:
|
||||
for ( idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
|
||||
idx = le16_to_cpu(cr->next_client)) {
|
||||
idx = le16_to_cpu( cr->next_client ) )
|
||||
{
|
||||
if ( !nr_clients || idx >= le16_to_cpu( ra->log_clients ) )
|
||||
goto err_out;
|
||||
/* Set @cr to the current log client record. */
|
||||
cr = ca + idx;
|
||||
/* The first log client record must not have a prev_client. */
|
||||
if (idx_is_first) {
|
||||
if ( idx_is_first )
|
||||
{
|
||||
if ( cr->prev_client != LOGFILE_NO_CLIENT )
|
||||
goto err_out;
|
||||
idx_is_first = FALSE;
|
||||
}
|
||||
}
|
||||
/* Switch to and check the in use list if we just did the free list. */
|
||||
if (in_free_list) {
|
||||
if ( in_free_list )
|
||||
{
|
||||
in_free_list = FALSE;
|
||||
idx = le16_to_cpu( ra->client_in_use_list );
|
||||
goto check_list;
|
||||
@ -359,12 +378,14 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
/* Check the restart page header for consistency. */
|
||||
if (!ntfs_check_restart_page_header(rp, pos)) {
|
||||
if ( !ntfs_check_restart_page_header( rp, pos ) )
|
||||
{
|
||||
/* Error output already done inside the function. */
|
||||
return EINVAL;
|
||||
}
|
||||
/* Check the restart area for consistency. */
|
||||
if (!ntfs_check_restart_area(rp)) {
|
||||
if ( !ntfs_check_restart_area( rp ) )
|
||||
{
|
||||
/* Error output already done inside the function. */
|
||||
return EINVAL;
|
||||
}
|
||||
@ -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 ) );
|
||||
else if ( ntfs_attr_pread( log_na, pos,
|
||||
le32_to_cpu( rp->system_page_size ), trp ) !=
|
||||
le32_to_cpu(rp->system_page_size)) {
|
||||
le32_to_cpu( rp->system_page_size ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_error( "Failed to read whole restart page into the "
|
||||
"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 ) )
|
||||
&& 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
|
||||
* 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 ) +
|
||||
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 "
|
||||
"detected in $LogFile restart page.\n" );
|
||||
err = EINVAL;
|
||||
@ -421,13 +445,16 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
*/
|
||||
err = 0;
|
||||
if ( ntfs_is_rstr_record( rp->magic ) &&
|
||||
ra->client_in_use_list != LOGFILE_NO_CLIENT) {
|
||||
if (!ntfs_check_log_client_array(trp)) {
|
||||
ra->client_in_use_list != LOGFILE_NO_CLIENT )
|
||||
{
|
||||
if ( !ntfs_check_log_client_array( trp ) )
|
||||
{
|
||||
err = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
if (lsn) {
|
||||
if ( lsn )
|
||||
{
|
||||
if ( ntfs_is_rstr_record( rp->magic ) )
|
||||
*lsn = sle64_to_cpu( ra->current_lsn );
|
||||
else /* if (ntfs_is_chkd_record(rp->magic)) */
|
||||
@ -436,7 +463,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
ntfs_log_trace( "Done.\n" );
|
||||
if ( wrp )
|
||||
*wrp = trp;
|
||||
else {
|
||||
else
|
||||
{
|
||||
err_out:
|
||||
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.
|
||||
*/
|
||||
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" );
|
||||
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
|
||||
* to be empty.
|
||||
*/
|
||||
for (pos = 0; pos < size; pos <<= 1) {
|
||||
for ( pos = 0; pos < size; pos <<= 1 )
|
||||
{
|
||||
/*
|
||||
* Read first NTFS_BLOCK_SIZE bytes of potential restart page.
|
||||
*/
|
||||
if ( ntfs_attr_pread( log_na, pos, NTFS_BLOCK_SIZE, kaddr ) !=
|
||||
NTFS_BLOCK_SIZE) {
|
||||
NTFS_BLOCK_SIZE )
|
||||
{
|
||||
ntfs_log_error( "Failed to read first NTFS_BLOCK_SIZE "
|
||||
"bytes of potential restart page.\n" );
|
||||
goto err_out;
|
||||
@ -538,7 +569,8 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
break;
|
||||
/* If not a (modified by chkdsk) restart page, continue. */
|
||||
if ( !ntfs_is_rstr_recordp( ( le32* )kaddr ) &&
|
||||
!ntfs_is_chkd_recordp((le32*)kaddr)) {
|
||||
!ntfs_is_chkd_recordp( ( le32* )kaddr ) )
|
||||
{
|
||||
if ( !pos )
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
continue;
|
||||
@ -552,12 +584,14 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
( RESTART_PAGE_HEADER* )kaddr, pos,
|
||||
!rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
||||
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn );
|
||||
if (!err) {
|
||||
if ( !err )
|
||||
{
|
||||
/*
|
||||
* If we have now found the first (modified by chkdsk)
|
||||
* restart page, continue looking for the second one.
|
||||
*/
|
||||
if (!pos) {
|
||||
if ( !pos )
|
||||
{
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
continue;
|
||||
}
|
||||
@ -578,17 +612,20 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
if ( !pos )
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
}
|
||||
if (kaddr) {
|
||||
if ( kaddr )
|
||||
{
|
||||
free( kaddr );
|
||||
kaddr = NULL;
|
||||
}
|
||||
if (logfile_is_empty) {
|
||||
if ( logfile_is_empty )
|
||||
{
|
||||
NVolSetLogFileEmpty( vol );
|
||||
is_empty:
|
||||
ntfs_log_trace( "Done. ($LogFile is empty.)\n" );
|
||||
return TRUE;
|
||||
}
|
||||
if (!rstr1_ph) {
|
||||
if ( !rstr1_ph )
|
||||
{
|
||||
if ( rstr2_ph )
|
||||
ntfs_log_error( "BUG: rstr2_ph isn't NULL!\n" );
|
||||
ntfs_log_error( "Did not find any restart pages in "
|
||||
@ -596,18 +633,22 @@ is_empty:
|
||||
return FALSE;
|
||||
}
|
||||
/* If both restart pages were found, use the more recent one. */
|
||||
if (rstr2_ph) {
|
||||
if ( rstr2_ph )
|
||||
{
|
||||
/*
|
||||
* If the second restart area is more recent, switch to it.
|
||||
* Otherwise just throw it away.
|
||||
*/
|
||||
if (rstr2_lsn > rstr1_lsn) {
|
||||
if ( rstr2_lsn > rstr1_lsn )
|
||||
{
|
||||
ntfs_log_debug( "Using second restart page as it is more "
|
||||
"recent.\n" );
|
||||
free( rstr1_ph );
|
||||
rstr1_ph = rstr2_ph;
|
||||
/* rstr1_lsn = rstr2_lsn; */
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug( "Using first restart page as it is more "
|
||||
"recent.\n" );
|
||||
free( rstr2_ph );
|
||||
@ -654,16 +695,19 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
/* An empty $LogFile must have been clean before it got emptied. */
|
||||
if (NVolLogFileEmpty(log_na->ni->vol)) {
|
||||
if ( NVolLogFileEmpty( log_na->ni->vol ) )
|
||||
{
|
||||
ntfs_log_trace( "$LogFile is empty\n" );
|
||||
return TRUE;
|
||||
}
|
||||
if (!rp) {
|
||||
if ( !rp )
|
||||
{
|
||||
ntfs_log_error( "Restart page header is NULL\n" );
|
||||
return FALSE;
|
||||
}
|
||||
if ( !ntfs_is_rstr_record( rp->magic ) &&
|
||||
!ntfs_is_chkd_record(rp->magic)) {
|
||||
!ntfs_is_chkd_record( rp->magic ) )
|
||||
{
|
||||
ntfs_log_error( "Restart page buffer is invalid\n" );
|
||||
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.
|
||||
*/
|
||||
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, "
|
||||
"%d).\n", le16_to_cpu( ra->client_in_use_list ),
|
||||
le16_to_cpu( ra->flags ) );
|
||||
@ -707,7 +752,8 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
||||
if ( NVolLogFileEmpty( na->ni->vol ) )
|
||||
return 0;
|
||||
|
||||
if (!NAttrNonResident(na)) {
|
||||
if ( !NAttrNonResident( na ) )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Resident $LogFile $DATA attribute" );
|
||||
return -1;
|
||||
@ -716,13 +762,15 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
||||
memset( buf, -1, NTFS_BUF_SIZE );
|
||||
|
||||
pos = 0;
|
||||
while ((count = na->data_size - pos) > 0) {
|
||||
while ( ( count = na->data_size - pos ) > 0 )
|
||||
{
|
||||
|
||||
if ( count > NTFS_BUF_SIZE )
|
||||
count = NTFS_BUF_SIZE;
|
||||
|
||||
count = ntfs_attr_pwrite( na, pos, count, buf );
|
||||
if (count <= 0) {
|
||||
if ( count <= 0 )
|
||||
{
|
||||
ntfs_log_perror( "Failed to reset $LogFile" );
|
||||
if ( count != -1 )
|
||||
errno = EIO;
|
||||
|
@ -61,10 +61,12 @@
|
||||
*
|
||||
* Begins the restart area.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
||||
/* 0*/
|
||||
NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
||||
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
When creating, set this to be immediately
|
||||
after this header structure (without any
|
||||
@ -108,7 +110,8 @@ typedef struct {
|
||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||
* information about the log file in which they are present.
|
||||
*/
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16( 0x0002 ),
|
||||
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
|
||||
} __attribute__( ( __packed__ ) );
|
||||
@ -122,9 +125,11 @@ typedef le16 RESTART_AREA_FLAGS;
|
||||
* RESTART_PAGE_HEADER to the restart_area_offset value found in it.
|
||||
* See notes at restart_area_offset above.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||
/* 0*/
|
||||
leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||
when the restart area was last written.
|
||||
This happens often but what is the interval?
|
||||
Is it just fixed time or is it every time a
|
||||
@ -262,9 +267,11 @@ typedef struct {
|
||||
* The offset of this record is found by adding the offset of the
|
||||
* RESTART_AREA to the client_array_offset value found in it.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||
/* 0*/
|
||||
leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||
set to 0. */
|
||||
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||
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
|
||||
* this specified anywhere?).
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
||||
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
@ -314,15 +322,18 @@ typedef struct {
|
||||
alignment). */
|
||||
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
|
||||
union {
|
||||
union
|
||||
{
|
||||
LSN last_lsn;
|
||||
s64 file_offset;
|
||||
} __attribute__( ( __packed__ ) ) copy;
|
||||
u32 flags;
|
||||
u16 page_count;
|
||||
u16 page_position;
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 next_record_offset;
|
||||
u8 reserved[6];
|
||||
LSN last_end_lsn;
|
||||
@ -335,7 +346,8 @@ typedef struct {
|
||||
*
|
||||
* (Or is it log record pages?)
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16( 0x0001 ), /* ??? */
|
||||
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
||||
/* This has nothing to do with the log record. It is only so
|
||||
@ -345,7 +357,8 @@ typedef enum {
|
||||
/**
|
||||
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u16 seq_number;
|
||||
u16 client_index;
|
||||
} __attribute__( ( __packed__ ) ) LOG_CLIENT_ID;
|
||||
@ -355,7 +368,8 @@ typedef struct {
|
||||
*
|
||||
* Each log record seems to have a constant size of 0x70 bytes.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
LSN this_lsn;
|
||||
LSN client_previous_lsn;
|
||||
LSN client_undo_next_lsn;
|
||||
@ -381,7 +395,8 @@ typedef struct {
|
||||
u32 alignment_or_reserved;
|
||||
VCN target_vcn;
|
||||
/* Now at ofs 0x50. */
|
||||
struct { /* Only present if lcns_to_follow
|
||||
struct
|
||||
{ /* Only present if lcns_to_follow
|
||||
is not 0. */
|
||||
LCN lcn;
|
||||
} __attribute__( ( __packed__ ) ) lcn_list[0];
|
||||
|
@ -67,7 +67,8 @@ static int tab;
|
||||
* @flags: Flags which affect the output style
|
||||
* @handler: Function to perform the actual logging
|
||||
*/
|
||||
struct ntfs_logging {
|
||||
struct ntfs_logging
|
||||
{
|
||||
u32 levels;
|
||||
u32 flags;
|
||||
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
|
||||
@ -77,7 +78,8 @@ struct ntfs_logging {
|
||||
* ntfs_log
|
||||
* 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
|
||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
||||
NTFS_LOG_LEVEL_LEAVE |
|
||||
@ -201,7 +203,8 @@ static FILE * ntfs_log_get_stream(u32 level)
|
||||
{
|
||||
FILE *stream;
|
||||
|
||||
switch (level) {
|
||||
switch ( level )
|
||||
{
|
||||
case NTFS_LOG_LEVEL_INFO:
|
||||
case NTFS_LOG_LEVEL_QUIET:
|
||||
case NTFS_LOG_LEVEL_PROGRESS:
|
||||
@ -237,7 +240,8 @@ static const char * ntfs_log_get_prefix(u32 level)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
switch (level) {
|
||||
switch ( level )
|
||||
{
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
prefix = "DEBUG: ";
|
||||
break;
|
||||
@ -286,13 +290,15 @@ static const char * ntfs_log_get_prefix(u32 level)
|
||||
*/
|
||||
void ntfs_log_set_handler( ntfs_log_handler *handler )
|
||||
{
|
||||
if (handler) {
|
||||
if ( handler )
|
||||
{
|
||||
ntfs_log.handler = handler;
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
if ( handler == ntfs_log_handler_syslog )
|
||||
openlog( "ntfs-3g", LOG_PID, LOG_USER );
|
||||
#endif
|
||||
} else
|
||||
}
|
||||
else
|
||||
ntfs_log.handler = ntfs_log_handler_null;
|
||||
}
|
||||
|
||||
@ -369,13 +375,15 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
return 1;
|
||||
#endif
|
||||
ret = vsnprintf( logbuf, LOG_LINE_LEN, format, args );
|
||||
if (ret < 0) {
|
||||
if ( ret < 0 )
|
||||
{
|
||||
vsyslog( LOG_NOTICE, format, args );
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
||||
if ( ( LOG_LINE_LEN > ret + 3 ) && ( level & NTFS_LOG_LEVEL_PERROR ) )
|
||||
{
|
||||
strncat( logbuf, ": ", LOG_LINE_LEN - ret - 1 );
|
||||
strncat( logbuf, strerror( olderr ), LOG_LINE_LEN - ( ret + 3 ) );
|
||||
ret = strlen( logbuf );
|
||||
@ -424,7 +432,8 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
stream = ( FILE* )data;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (level == NTFS_LOG_LEVEL_LEAVE) {
|
||||
if ( level == NTFS_LOG_LEVEL_LEAVE )
|
||||
{
|
||||
if ( tab )
|
||||
tab--;
|
||||
return 0;
|
||||
@ -593,16 +602,23 @@ int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||
*/
|
||||
BOOL ntfs_log_parse_option( const char *option )
|
||||
{
|
||||
if (strcmp(option, "--log-debug") == 0) {
|
||||
if ( strcmp( option, "--log-debug" ) == 0 )
|
||||
{
|
||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_DEBUG );
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-verbose") == 0) {
|
||||
}
|
||||
else if ( strcmp( option, "--log-verbose" ) == 0 )
|
||||
{
|
||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_VERBOSE );
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-quiet") == 0) {
|
||||
}
|
||||
else if ( strcmp( option, "--log-quiet" ) == 0 )
|
||||
{
|
||||
ntfs_log_clear_levels( NTFS_LOG_LEVEL_QUIET );
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-trace") == 0) {
|
||||
}
|
||||
else if ( strcmp( option, "--log-trace" ) == 0 )
|
||||
{
|
||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_TRACE );
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -24,11 +24,13 @@
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static inline void* ntfs_alloc (size_t size) {
|
||||
static inline void* ntfs_alloc ( size_t size )
|
||||
{
|
||||
return malloc( size );
|
||||
}
|
||||
|
||||
static inline void* ntfs_align (size_t size) {
|
||||
static inline void* ntfs_align ( size_t size )
|
||||
{
|
||||
#ifdef __wii__
|
||||
return memalign( 32, size );
|
||||
#else
|
||||
@ -36,7 +38,8 @@ static inline void* ntfs_align (size_t size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ntfs_free (void* mem) {
|
||||
static inline void ntfs_free ( void* mem )
|
||||
{
|
||||
free( mem );
|
||||
}
|
||||
|
||||
|
@ -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 ) );
|
||||
|
||||
if (!vol || !vol->mft_na || !b || count < 0) {
|
||||
if ( !vol || !vol->mft_na || !b || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: b=%p count=%lld mft=%llu", __FUNCTION__,
|
||||
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 );
|
||||
/* Refuse to read non-allocated mft records. */
|
||||
if ( m + count > vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits) {
|
||||
vol->mft_record_size_bits )
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror( "Trying to read non-allocated mft records "
|
||||
"(%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,
|
||||
count, vol->mft_record_size, b );
|
||||
if (br != count) {
|
||||
if ( br != count )
|
||||
{
|
||||
if ( br != -1 )
|
||||
errno = EIO;
|
||||
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;
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
m = MREF( mref );
|
||||
/* Refuse to write non-allocated mft records. */
|
||||
if ( m + count > vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits) {
|
||||
vol->mft_record_size_bits )
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror( "Trying to write non-allocated mft records "
|
||||
"(%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 );
|
||||
return -1;
|
||||
}
|
||||
if (m < vol->mftmirr_size) {
|
||||
if (!vol->mftmirr_na) {
|
||||
if ( m < vol->mftmirr_size )
|
||||
{
|
||||
if ( !vol->mftmirr_na )
|
||||
{
|
||||
errno = EINVAL;
|
||||
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,
|
||||
count, vol->mft_record_size, b );
|
||||
if (bw != count) {
|
||||
if ( bw != count )
|
||||
{
|
||||
if ( bw != -1 )
|
||||
errno = EIO;
|
||||
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)" );
|
||||
res = errno;
|
||||
}
|
||||
if (bmirr && bw > 0) {
|
||||
if ( bmirr && bw > 0 )
|
||||
{
|
||||
if ( bw < cnt )
|
||||
cnt = bw;
|
||||
bw = ntfs_attr_mst_pwrite( vol->mftmirr_na,
|
||||
m << vol->mft_record_size_bits, cnt,
|
||||
vol->mft_record_size, bmirr );
|
||||
if (bw != cnt) {
|
||||
if ( bw != cnt )
|
||||
{
|
||||
if ( bw != -1 )
|
||||
errno = EIO;
|
||||
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;
|
||||
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",
|
||||
( unsigned long long )MREF( mref ), *( le32 * )m );
|
||||
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 "
|
||||
"(%u <> %u)\n", ( unsigned long long )MREF( mref ),
|
||||
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 ) );
|
||||
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",
|
||||
( unsigned long long )MREF( mref ) );
|
||||
goto err_out;
|
||||
@ -279,14 +292,16 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||
{
|
||||
MFT_RECORD *m;
|
||||
|
||||
if (!vol || !mrec) {
|
||||
if ( !vol || !mrec )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = *mrec;
|
||||
if (!m) {
|
||||
if ( !m )
|
||||
{
|
||||
m = ntfs_malloc( vol->mft_record_size );
|
||||
if ( !m )
|
||||
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 ) )
|
||||
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",
|
||||
( unsigned long long )MREF( mref ), MSEQNO( mref ),
|
||||
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;
|
||||
|
||||
if (!vol || !mrec) {
|
||||
if ( !vol || !mrec )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
|
||||
return -1;
|
||||
@ -340,9 +357,11 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
/* Aligned to 2-byte boundary. */
|
||||
if ( vol->major_ver < 3 || ( vol->major_ver == 3 && !vol->minor_ver ) )
|
||||
mrec->usa_ofs = cpu_to_le16( ( sizeof( MFT_RECORD_OLD ) + 1 ) & ~1 );
|
||||
else {
|
||||
else
|
||||
{
|
||||
/* Abort if mref is > 32 bits. */
|
||||
if (MREF(mref) & 0x0000ffff00000000ull) {
|
||||
if ( MREF( mref ) & 0x0000ffff00000000ull )
|
||||
{
|
||||
errno = ERANGE;
|
||||
ntfs_log_perror( "Mft reference exceeds 32 bits" );
|
||||
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 )
|
||||
mrec->usa_count = cpu_to_le16( vol->mft_record_size /
|
||||
NTFS_BLOCK_SIZE + 1 );
|
||||
else {
|
||||
else
|
||||
{
|
||||
mrec->usa_count = cpu_to_le16( 1 );
|
||||
ntfs_log_error( "Sector size is bigger than MFT record size. "
|
||||
"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;
|
||||
if ( 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;
|
||||
pass = 2;
|
||||
/* This happens on a freshly formatted volume. */
|
||||
if (data_pos >= pass_end) {
|
||||
if ( data_pos >= pass_end )
|
||||
{
|
||||
errno = ENOSPC;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (ntfs_is_mft(base_ni)) {
|
||||
if ( ntfs_is_mft( base_ni ) )
|
||||
{
|
||||
data_pos = 0;
|
||||
pass = 2;
|
||||
}
|
||||
@ -529,21 +552,24 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
b = 0;
|
||||
#endif
|
||||
/* 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. */
|
||||
ofs = data_pos >> 3;
|
||||
ll = ( ( pass_end + 7 ) >> 3 ) - ofs;
|
||||
if ( size > ll )
|
||||
size = ll;
|
||||
ll = ntfs_attr_pread( mftbmp_na, ofs, size, buf );
|
||||
if (ll < 0) {
|
||||
if ( ll < 0 )
|
||||
{
|
||||
ntfs_log_perror( "Failed to read $MFT bitmap" );
|
||||
free( buf );
|
||||
goto leave;
|
||||
}
|
||||
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 (ll) {
|
||||
if ( ll )
|
||||
{
|
||||
size = ll << 3;
|
||||
bit = data_pos & 7;
|
||||
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,
|
||||
byte ? *byte : -1, b );
|
||||
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
|
||||
* 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. */
|
||||
b = ntfs_ffz( ( unsigned long ) * byte );
|
||||
if (b < 8 && b >= (bit & 7)) {
|
||||
if ( b < 8 && b >= ( bit & 7 ) )
|
||||
{
|
||||
free( buf );
|
||||
ret = data_pos + ( bit & ~7ull ) + b;
|
||||
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. */
|
||||
pass++;
|
||||
if (pass == 2) {
|
||||
if ( pass == 2 )
|
||||
{
|
||||
/*
|
||||
* Starting the second pass, in which we scan the first
|
||||
* 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;
|
||||
ntfs_log_enter( "Entering\n" );
|
||||
|
||||
if (!NInoAttrList(na->ni)) {
|
||||
if (ntfs_inode_add_attrlist(na->ni)) {
|
||||
if ( !NInoAttrList( na->ni ) )
|
||||
{
|
||||
if ( ntfs_inode_add_attrlist( na->ni ) )
|
||||
{
|
||||
ntfs_log_perror( "%s: Can not add attrlist #3", __FUNCTION__ );
|
||||
goto out;
|
||||
}
|
||||
@ -627,7 +658,8 @@ static int ntfs_mft_attr_extend(ntfs_attr *na)
|
||||
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__ );
|
||||
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 ) >>
|
||||
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 "
|
||||
"cluster of mft bitmap attribute.\n" );
|
||||
if ( rl )
|
||||
@ -673,13 +706,15 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
||||
lcn = rl->lcn + rl->length;
|
||||
|
||||
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 "
|
||||
"the mft bitmap.\n" );
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
rl = ntfs_runlists_merge( mftbmp_na->rl, rl2 );
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_error( "Failed to merge runlists for mft "
|
||||
"bitmap.\n" );
|
||||
@ -704,7 +739,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
||||
goto undo_alloc;
|
||||
|
||||
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 "
|
||||
"mft bitmap attribute.\n" );
|
||||
goto undo_alloc;
|
||||
@ -713,7 +749,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
||||
a = ctx->attr;
|
||||
ll = sle64_to_cpu( a->lowest_vcn );
|
||||
rl2 = ntfs_attr_find_vcn( mftbmp_na, ll );
|
||||
if (!rl2 || !rl2->length) {
|
||||
if ( !rl2 || !rl2->length )
|
||||
{
|
||||
ntfs_log_error( "Failed to determine previous last "
|
||||
"allocated cluster of mft bitmap attribute.\n" );
|
||||
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. */
|
||||
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 "
|
||||
"mft bitmap attribute extent.\n" );
|
||||
goto undo_alloc;
|
||||
@ -730,12 +768,14 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
||||
/* Expand the attribute record if necessary. */
|
||||
old_alen = le32_to_cpu( a->length );
|
||||
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" );
|
||||
ret = ntfs_mft_attr_extend( vol->mftbmp_na );
|
||||
if ( ret == STATUS_OK )
|
||||
goto ok;
|
||||
if (ret == STATUS_ERROR) {
|
||||
if ( ret == STATUS_ERROR )
|
||||
{
|
||||
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
|
||||
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. */
|
||||
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
||||
le16_to_cpu( a->mapping_pairs_offset ), mp_size, rl2, ll,
|
||||
NULL)) {
|
||||
NULL ) )
|
||||
{
|
||||
ntfs_log_error( "Failed to build mapping pairs array for "
|
||||
"mft bitmap attribute.\n" );
|
||||
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.
|
||||
* 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
|
||||
* 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_attr_reinit_search_ctx( ctx );
|
||||
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 mft bitmap attribute.\n" );
|
||||
goto restore_undo_alloc;
|
||||
@ -784,7 +827,8 @@ restore_undo_alloc:
|
||||
err = errno;
|
||||
ntfs_attr_reinit_search_ctx( ctx );
|
||||
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 "
|
||||
"mft bitmap attribute.%s\n", es );
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
@ -813,7 +857,8 @@ undo_alloc:
|
||||
ntfs_log_error( "Failed to free cluster.%s\n", es );
|
||||
else
|
||||
vol->free_clusters++;
|
||||
if (mp_rebuilt) {
|
||||
if ( mp_rebuilt )
|
||||
{
|
||||
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
||||
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 );
|
||||
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
||||
}
|
||||
if (update_mp) {
|
||||
if ( update_mp )
|
||||
{
|
||||
if ( ntfs_attr_update_mapping_pairs( vol->mftbmp_na, 0 ) )
|
||||
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
|
||||
}
|
||||
@ -884,7 +930,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
||||
goto out;
|
||||
|
||||
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 "
|
||||
"mft bitmap attribute.\n" );
|
||||
err = errno;
|
||||
@ -895,7 +942,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
||||
old_initialized_size = mftbmp_na->initialized_size;
|
||||
mftbmp_na->initialized_size += 8;
|
||||
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;
|
||||
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. */
|
||||
ll = 0;
|
||||
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" );
|
||||
vol->free_mft_records += ( 8 * 8 );
|
||||
ret = 0;
|
||||
@ -921,7 +970,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
||||
goto err_out;
|
||||
|
||||
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 "
|
||||
"mft bitmap attribute.%s\n", es );
|
||||
put_err_out:
|
||||
@ -931,7 +981,8 @@ put_err_out:
|
||||
a = ctx->attr;
|
||||
mftbmp_na->initialized_size = 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;
|
||||
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,
|
||||
( 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 "
|
||||
"cluster of mft data attribute.\n" );
|
||||
if ( rl )
|
||||
@ -1009,11 +1061,13 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
||||
nr = min_nr;
|
||||
|
||||
old_last_vcn = rl[1].vcn;
|
||||
do {
|
||||
do
|
||||
{
|
||||
rl2 = ntfs_cluster_alloc( vol, old_last_vcn, nr, lcn, MFT_ZONE );
|
||||
if ( rl2 )
|
||||
break;
|
||||
if (errno != ENOSPC || nr == min_nr) {
|
||||
if ( errno != ENOSPC || nr == min_nr )
|
||||
{
|
||||
ntfs_log_perror( "Failed to allocate (%lld) clusters "
|
||||
"for $MFT", ( long long )nr );
|
||||
goto out;
|
||||
@ -1026,12 +1080,14 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
||||
nr = min_nr;
|
||||
ntfs_log_debug( "Retrying mft data allocation with minimal cluster "
|
||||
"count %lli.\n", ( long long )nr );
|
||||
} while (1);
|
||||
}
|
||||
while ( 1 );
|
||||
|
||||
ntfs_log_debug( "Allocated %lld clusters.\n", ( long long )nr );
|
||||
|
||||
rl = ntfs_runlists_merge( mft_na->rl, rl2 );
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_error( "Failed to merge runlists for mft data "
|
||||
"attribute.\n" );
|
||||
@ -1053,7 +1109,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
||||
goto undo_alloc;
|
||||
|
||||
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 "
|
||||
"mft data attribute.\n" );
|
||||
goto undo_alloc;
|
||||
@ -1062,7 +1119,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
||||
a = ctx->attr;
|
||||
ll = sle64_to_cpu( a->lowest_vcn );
|
||||
rl2 = ntfs_attr_find_vcn( mft_na, ll );
|
||||
if (!rl2 || !rl2->length) {
|
||||
if ( !rl2 || !rl2->length )
|
||||
{
|
||||
ntfs_log_error( "Failed to determine previous last "
|
||||
"allocated cluster of mft data attribute.\n" );
|
||||
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. */
|
||||
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 "
|
||||
"mft data attribute extent.\n" );
|
||||
goto undo_alloc;
|
||||
@ -1079,11 +1138,13 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
||||
/* Expand the attribute record if necessary. */
|
||||
old_alen = le32_to_cpu( a->length );
|
||||
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 );
|
||||
if ( ret == STATUS_OK )
|
||||
goto ok;
|
||||
if (ret == STATUS_ERROR) {
|
||||
if ( ret == STATUS_ERROR )
|
||||
{
|
||||
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
|
||||
update_mp = TRUE;
|
||||
}
|
||||
@ -1095,7 +1156,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
||||
*/
|
||||
if ( ntfs_mapping_pairs_build( vol,
|
||||
( 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 "
|
||||
"mft data attribute.\n" );
|
||||
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
|
||||
* attribute.
|
||||
*/
|
||||
if (a->lowest_vcn) {
|
||||
if ( a->lowest_vcn )
|
||||
{
|
||||
/*
|
||||
* We are not in the first attribute extent, switch to it, but
|
||||
* 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_attr_reinit_search_ctx( ctx );
|
||||
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 "
|
||||
"extent of mft data attribute.\n" );
|
||||
goto restore_undo_alloc;
|
||||
@ -1139,7 +1203,8 @@ restore_undo_alloc:
|
||||
err = errno;
|
||||
ntfs_attr_reinit_search_ctx( ctx );
|
||||
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 "
|
||||
"mft data attribute.%s\n", es );
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
@ -1164,7 +1229,8 @@ undo_alloc:
|
||||
if ( ntfs_rl_truncate( &mft_na->rl, old_last_vcn ) )
|
||||
ntfs_log_error( "Failed to truncate mft data attribute "
|
||||
"runlist.%s\n", es );
|
||||
if (mp_rebuilt) {
|
||||
if ( mp_rebuilt )
|
||||
{
|
||||
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
||||
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 );
|
||||
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
||||
}
|
||||
if (update_mp) {
|
||||
if ( update_mp )
|
||||
{
|
||||
if ( ntfs_attr_update_mapping_pairs( vol->mft_na, 0 ) )
|
||||
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->data_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 )
|
||||
goto out;
|
||||
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
|
||||
* 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;
|
||||
mft_na->initialized_size += vol->mft_record_size;
|
||||
if ( mft_na->initialized_size > mft_na->data_size )
|
||||
mft_na->data_size = mft_na->initialized_size;
|
||||
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" );
|
||||
goto undo_data_init;
|
||||
}
|
||||
@ -1252,7 +1322,8 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
|
||||
goto undo_data_init;
|
||||
|
||||
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 "
|
||||
"mft data attribute.\n" );
|
||||
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;
|
||||
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;
|
||||
ntfs_log_perror( "%s: unexpected $MFT sizes, see below", __FUNCTION__ );
|
||||
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;
|
||||
|
||||
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 "
|
||||
"mft data attribute.\n" );
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
@ -1384,7 +1457,8 @@ static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
|
||||
goto err_out;
|
||||
|
||||
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" );
|
||||
goto err_out;
|
||||
}
|
||||
@ -1403,12 +1477,14 @@ found_free_rec:
|
||||
if ( !m )
|
||||
goto undo_mftbmp_alloc;
|
||||
|
||||
if (ntfs_mft_record_read(vol, bit, m)) {
|
||||
if ( ntfs_mft_record_read( vol, bit, m ) )
|
||||
{
|
||||
free( m );
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
/* 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 "
|
||||
"$MFT bitmap. Fixed.\n", ( long long )bit );
|
||||
free( m );
|
||||
@ -1417,7 +1493,8 @@ found_free_rec:
|
||||
|
||||
seq_no = m->sequence_number;
|
||||
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" );
|
||||
free( m );
|
||||
goto undo_mftbmp_alloc;
|
||||
@ -1431,7 +1508,8 @@ found_free_rec:
|
||||
m->flags |= MFT_RECORD_IN_USE;
|
||||
/* Now need to open an ntfs inode for the mft record. */
|
||||
ni = ntfs_inode_allocate( vol );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfs_log_error( "Failed to allocate buffer for inode.\n" );
|
||||
free( m );
|
||||
goto undo_mftbmp_alloc;
|
||||
@ -1451,18 +1529,21 @@ found_free_rec:
|
||||
* Attach the extent inode to the base inode, reallocating
|
||||
* memory if needed.
|
||||
*/
|
||||
if (!(base_ni->nr_extents & 3)) {
|
||||
if ( !( base_ni->nr_extents & 3 ) )
|
||||
{
|
||||
ntfs_inode **extent_nis;
|
||||
int i;
|
||||
|
||||
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
||||
extent_nis = ntfs_malloc( i );
|
||||
if (!extent_nis) {
|
||||
if ( !extent_nis )
|
||||
{
|
||||
free( m );
|
||||
free( ni );
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
if (base_ni->nr_extents) {
|
||||
if ( base_ni->nr_extents )
|
||||
{
|
||||
memcpy( extent_nis, base_ni->extent_nis,
|
||||
i - 4 * sizeof( ntfs_inode * ) );
|
||||
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 );
|
||||
else
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ntfs_is_mft(base_ni)) {
|
||||
if ( ntfs_is_mft( base_ni ) )
|
||||
{
|
||||
ni = ntfs_mft_rec_alloc( vol );
|
||||
goto out;
|
||||
}
|
||||
@ -1613,7 +1696,8 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
mftbmp_na = vol->mftbmp_na;
|
||||
retry:
|
||||
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",
|
||||
( long long )bit );
|
||||
goto found_free_rec;
|
||||
@ -1630,7 +1714,8 @@ retry:
|
||||
*/
|
||||
ll = mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||
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;
|
||||
if ( bit < RESERVED_MFT_RECORDS )
|
||||
bit = RESERVED_MFT_RECORDS;
|
||||
@ -1648,13 +1733,15 @@ retry:
|
||||
( long long )mftbmp_na->allocated_size,
|
||||
( long long )mftbmp_na->data_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 );
|
||||
|
||||
if ( ret == STATUS_ERROR )
|
||||
goto err_out;
|
||||
if (ret == STATUS_KEEP_SEARCHING) {
|
||||
if ( ret == STATUS_KEEP_SEARCHING )
|
||||
{
|
||||
ret = ntfs_mft_bitmap_extend_allocation( vol );
|
||||
if ( ret != STATUS_OK )
|
||||
goto err_out;
|
||||
@ -1684,7 +1771,8 @@ retry:
|
||||
ntfs_log_debug( "found free record (#3) at %lld\n", ( long long )bit );
|
||||
found_free_rec:
|
||||
/* @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" );
|
||||
goto err_out;
|
||||
}
|
||||
@ -1705,12 +1793,14 @@ found_free_rec:
|
||||
if ( !m )
|
||||
goto undo_mftbmp_alloc;
|
||||
|
||||
if (ntfs_mft_record_read(vol, bit, m)) {
|
||||
if ( ntfs_mft_record_read( vol, bit, m ) )
|
||||
{
|
||||
free( m );
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
/* 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 "
|
||||
"$MFT bitmap. Fixed.\n", ( long long )bit );
|
||||
free( m );
|
||||
@ -1718,7 +1808,8 @@ found_free_rec:
|
||||
}
|
||||
seq_no = m->sequence_number;
|
||||
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" );
|
||||
free( m );
|
||||
goto undo_mftbmp_alloc;
|
||||
@ -1732,7 +1823,8 @@ found_free_rec:
|
||||
m->flags |= MFT_RECORD_IN_USE;
|
||||
/* Now need to open an ntfs inode for the mft record. */
|
||||
ni = ntfs_inode_allocate( vol );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfs_log_error( "Failed to allocate buffer for inode.\n" );
|
||||
free( m );
|
||||
goto undo_mftbmp_alloc;
|
||||
@ -1744,7 +1836,8 @@ found_free_rec:
|
||||
* extent inode and attach it to the base inode. Also, set the base
|
||||
* mft record reference in the extent inode.
|
||||
*/
|
||||
if (base_ni) {
|
||||
if ( base_ni )
|
||||
{
|
||||
ni->nr_extents = -1;
|
||||
ni->base_ni = base_ni;
|
||||
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
|
||||
* memory if needed.
|
||||
*/
|
||||
if (!(base_ni->nr_extents & 3)) {
|
||||
if ( !( base_ni->nr_extents & 3 ) )
|
||||
{
|
||||
ntfs_inode **extent_nis;
|
||||
int i;
|
||||
|
||||
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
||||
extent_nis = ntfs_malloc( i );
|
||||
if (!extent_nis) {
|
||||
if ( !extent_nis )
|
||||
{
|
||||
free( m );
|
||||
free( ni );
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
if (base_ni->nr_extents) {
|
||||
if ( base_ni->nr_extents )
|
||||
{
|
||||
memcpy( extent_nis, base_ni->extent_nis,
|
||||
i - 4 * sizeof( ntfs_inode * ) );
|
||||
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 );
|
||||
|
||||
if (!vol || !vol->mftbmp_na || !ni) {
|
||||
if ( !vol || !vol->mftbmp_na || !ni )
|
||||
{
|
||||
errno = EINVAL;
|
||||
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. */
|
||||
ntfs_inode_mark_dirty( ni );
|
||||
if (ntfs_inode_sync(ni)) {
|
||||
if ( ntfs_inode_sync( ni ) )
|
||||
{
|
||||
err = errno;
|
||||
goto sync_rollback;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
// FIXME: If ntfs_bitmap_clear_run() guarantees rollback on
|
||||
// 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. */
|
||||
#if CACHE_NIDATA_SIZE
|
||||
if (!ntfs_inode_real_close(ni)) {
|
||||
if ( !ntfs_inode_real_close( ni ) )
|
||||
{
|
||||
#else
|
||||
if (!ntfs_inode_close(ni)) {
|
||||
if ( !ntfs_inode_close( ni ) )
|
||||
{
|
||||
#endif
|
||||
vol->free_mft_records++;
|
||||
return 0;
|
||||
@ -1894,7 +1995,8 @@ int ntfs_mft_usn_dec(MFT_RECORD *mrec)
|
||||
u16 usn;
|
||||
le16 *usnp;
|
||||
|
||||
if (!mrec) {
|
||||
if ( !mrec )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
@ -61,7 +61,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
/* Size and alignment checks. */
|
||||
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
||||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: magic: 0x%08x size: %d usa_ofs: %d "
|
||||
"usa_count: %d", __FUNCTION__, *( le32 * )b,
|
||||
@ -85,8 +86,10 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
/*
|
||||
* Check for incomplete multi sector transfer(s).
|
||||
*/
|
||||
while (usa_count--) {
|
||||
if (*data_pos != usn) {
|
||||
while ( usa_count-- )
|
||||
{
|
||||
if ( *data_pos != usn )
|
||||
{
|
||||
/*
|
||||
* Incomplete multi sector transfer detected! )-:
|
||||
* Set the magic to "BAAD" and return failure.
|
||||
@ -106,7 +109,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
usa_count = le16_to_cpu( b->usa_count ) - 1;
|
||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while ( usa_count-- )
|
||||
{
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
@ -147,7 +151,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
|
||||
/* Sanity check + only fixup if it makes sense. */
|
||||
if ( !b || ntfs_is_baad_record( b->magic ) ||
|
||||
ntfs_is_hole_record(b->magic)) {
|
||||
ntfs_is_hole_record( b->magic ) )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: bad argument", __FUNCTION__ );
|
||||
return -1;
|
||||
@ -159,7 +164,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
/* Size and alignment checks. */
|
||||
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
||||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
||||
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. */
|
||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while ( usa_count-- )
|
||||
{
|
||||
/*
|
||||
* Increment the position in the usa and save the
|
||||
* original data from the data buffer into the usa.
|
||||
@ -217,7 +224,8 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
||||
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while ( usa_count-- )
|
||||
{
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
|
@ -41,7 +41,8 @@
|
||||
#include "cache.h"
|
||||
|
||||
// NTFS device driver devoptab
|
||||
static const devoptab_t devops_ntfs = {
|
||||
static const devoptab_t devops_ntfs =
|
||||
{
|
||||
NULL, /* Device name */
|
||||
sizeof ( ntfs_file_state ),
|
||||
ntfs_open_r,
|
||||
@ -72,7 +73,8 @@ void ntfsInit (void)
|
||||
static bool isInit = false;
|
||||
|
||||
// Initialise ntfs-3g (if not already done so)
|
||||
if (!isInit) {
|
||||
if ( !isInit )
|
||||
{
|
||||
isInit = true;
|
||||
|
||||
// Set the log handler
|
||||
@ -98,7 +100,8 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
sec_t part_lba = 0;
|
||||
int i;
|
||||
|
||||
union {
|
||||
union
|
||||
{
|
||||
u8 buffer[512];
|
||||
MASTER_BOOT_RECORD mbr;
|
||||
EXTENDED_BOOT_RECORD ebr;
|
||||
@ -106,7 +109,8 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
} sector;
|
||||
|
||||
// Sanity check
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -117,27 +121,32 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
ntfsInit();
|
||||
|
||||
// Start the device and check that it is inserted
|
||||
if (!interface->startup()) {
|
||||
if ( !interface->startup() )
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (!interface->isInserted()) {
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read the first sector on the device
|
||||
if (!interface->readSectors(0, 1, §or.buffer)) {
|
||||
if ( !interface->readSectors( 0, 1, §or.buffer ) )
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If this is the devices master boot record
|
||||
if (sector.mbr.signature == MBR_SIGNATURE) {
|
||||
if ( sector.mbr.signature == MBR_SIGNATURE )
|
||||
{
|
||||
memcpy( &mbr, §or, sizeof( MASTER_BOOT_RECORD ) );
|
||||
ntfs_log_debug( "Valid Master Boot Record found\n" );
|
||||
|
||||
// Search the partition table for all NTFS partitions (max. 4 primary partitions)
|
||||
for (i = 0; i < 4; i++) {
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
partition = &mbr.partitions[i];
|
||||
part_lba = le32_to_cpu( mbr.partitions[i].lba_start );
|
||||
|
||||
@ -146,25 +155,32 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
part_lba, partition->type );
|
||||
|
||||
// Figure out what type of partition this is
|
||||
switch (partition->type) {
|
||||
switch ( partition->type )
|
||||
{
|
||||
|
||||
// Ignore empty partitions
|
||||
case PARTITION_TYPE_EMPTY:
|
||||
continue;
|
||||
|
||||
// NTFS partition
|
||||
case PARTITION_TYPE_NTFS: {
|
||||
case PARTITION_TYPE_NTFS:
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Claims to be NTFS\n", i + 1 );
|
||||
|
||||
// Read and validate the NTFS partition
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1 );
|
||||
}
|
||||
}
|
||||
@ -175,17 +191,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
|
||||
// DOS 3.3+ or Windows 95 extended partition
|
||||
case PARTITION_TYPE_DOS33_EXTENDED:
|
||||
case PARTITION_TYPE_WIN95_EXTENDED: {
|
||||
case PARTITION_TYPE_WIN95_EXTENDED:
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Claims to be Extended\n", i + 1 );
|
||||
|
||||
// Walk the extended partition chain, finding all NTFS partitions within it
|
||||
sec_t ebr_lba = part_lba;
|
||||
sec_t next_erb_lba = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
|
||||
// Read and validate the extended boot record
|
||||
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or)) {
|
||||
if (sector.ebr.signature == EBR_SIGNATURE) {
|
||||
if ( interface->readSectors( ebr_lba + next_erb_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.ebr.signature == EBR_SIGNATURE )
|
||||
{
|
||||
ntfs_log_debug( "Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
||||
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||
sector.ebr.partition.type );
|
||||
@ -196,42 +216,54 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
next_erb_lba = le32_to_cpu( sector.ebr.next_ebr.lba_start );
|
||||
|
||||
// Check if this partition has a valid NTFS boot record
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba );
|
||||
if(sector.ebr.partition.type != PARTITION_TYPE_NTFS) {
|
||||
if ( sector.ebr.partition.type != PARTITION_TYPE_NTFS )
|
||||
{
|
||||
ntfs_log_warning( "Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS );
|
||||
}
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
next_erb_lba = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} while (next_erb_lba);
|
||||
}
|
||||
while ( next_erb_lba );
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Unknown or unsupported partition type
|
||||
default: {
|
||||
default:
|
||||
{
|
||||
|
||||
// Check if this partition has a valid NTFS boot record anyway,
|
||||
// it might be misrepresented due to a lazy partition editor
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
||||
if(partition->type != PARTITION_TYPE_NTFS) {
|
||||
if ( partition->type != PARTITION_TYPE_NTFS )
|
||||
{
|
||||
ntfs_log_warning( "Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS );
|
||||
}
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
@ -247,15 +279,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
}
|
||||
|
||||
// Else it is assumed this device has no master boot record
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug( "No Master Boot Record was found!\n" );
|
||||
|
||||
// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (interface->readSectors(i, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
for ( i = 0; i < 64; i++ )
|
||||
{
|
||||
if ( interface->readSectors( i, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Valid NTFS boot sector found at sector %d!\n", i );
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
partition_starts[partition_count] = i;
|
||||
partition_count++;
|
||||
}
|
||||
@ -269,9 +307,11 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
/*interface->shutdown();*/
|
||||
|
||||
// Return the found partitions (if any)
|
||||
if (partition_count > 0) {
|
||||
if ( partition_count > 0 )
|
||||
{
|
||||
*partitions = ( sec_t* )ntfs_alloc( sizeof( sec_t ) * partition_count );
|
||||
if (*partitions) {
|
||||
if ( *partitions )
|
||||
{
|
||||
memcpy( *partitions, &partition_starts, sizeof( sec_t ) * partition_count );
|
||||
return partition_count;
|
||||
}
|
||||
@ -295,25 +335,33 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
||||
ntfsInit();
|
||||
|
||||
// Find and mount all NTFS partitions on all known devices
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
||||
for ( i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++ )
|
||||
{
|
||||
disc = &discs[i];
|
||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
||||
if (partition_count > 0 && partitions) {
|
||||
for (j = 0, k = 0; j < partition_count; j++) {
|
||||
if ( partition_count > 0 && partitions )
|
||||
{
|
||||
for ( j = 0, k = 0; j < partition_count; j++ )
|
||||
{
|
||||
|
||||
// Find the next unused mount name
|
||||
do {
|
||||
do
|
||||
{
|
||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
||||
if (k >= NTFS_MAX_MOUNTS) {
|
||||
if ( k >= NTFS_MAX_MOUNTS )
|
||||
{
|
||||
ntfs_free( partitions );
|
||||
errno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
}
|
||||
} while (ntfsGetDevice(name, false));
|
||||
}
|
||||
while ( ntfsGetDevice( name, false ) );
|
||||
|
||||
// Mount the partition
|
||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||
if ( mount_count < NTFS_MAX_MOUNTS )
|
||||
{
|
||||
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
||||
{
|
||||
strcpy( mount_points[mount_count].name, name );
|
||||
mount_points[mount_count].interface = disc->interface;
|
||||
mount_points[mount_count].startSector = partitions[j];
|
||||
@ -327,9 +375,11 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
||||
}
|
||||
|
||||
// Return the mounts (if any)
|
||||
if (mount_count > 0 && mounts) {
|
||||
if ( mount_count > 0 && mounts )
|
||||
{
|
||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
||||
if (*mounts) {
|
||||
if ( *mounts )
|
||||
{
|
||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
||||
return mount_count;
|
||||
}
|
||||
@ -350,7 +400,8 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
||||
int i, j, k;
|
||||
|
||||
// Sanity check
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -359,26 +410,35 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
||||
ntfsInit();
|
||||
|
||||
// Find the specified device then find and mount all NTFS partitions on it
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
||||
if (discs[i].interface == interface) {
|
||||
for ( i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++ )
|
||||
{
|
||||
if ( discs[i].interface == interface )
|
||||
{
|
||||
disc = &discs[i];
|
||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
||||
if (partition_count > 0 && partitions) {
|
||||
for (j = 0, k = 0; j < partition_count; j++) {
|
||||
if ( partition_count > 0 && partitions )
|
||||
{
|
||||
for ( j = 0, k = 0; j < partition_count; j++ )
|
||||
{
|
||||
|
||||
// Find the next unused mount name
|
||||
do {
|
||||
do
|
||||
{
|
||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
||||
if (k >= NTFS_MAX_MOUNTS) {
|
||||
if ( k >= NTFS_MAX_MOUNTS )
|
||||
{
|
||||
ntfs_free( partitions );
|
||||
errno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
}
|
||||
} while (ntfsGetDevice(name, false));
|
||||
}
|
||||
while ( ntfsGetDevice( name, false ) );
|
||||
|
||||
// Mount the partition
|
||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||
if ( mount_count < NTFS_MAX_MOUNTS )
|
||||
{
|
||||
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
||||
{
|
||||
strcpy( mount_points[mount_count].name, name );
|
||||
mount_points[mount_count].interface = disc->interface;
|
||||
mount_points[mount_count].startSector = partitions[j];
|
||||
@ -394,15 +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 (!disc) {
|
||||
if ( !disc )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return the mounts (if any)
|
||||
if (mount_count > 0 && mounts) {
|
||||
if ( mount_count > 0 && mounts )
|
||||
{
|
||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
||||
if (*mounts) {
|
||||
if ( *mounts )
|
||||
{
|
||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
||||
return mount_count;
|
||||
}
|
||||
@ -417,7 +480,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
gekko_fd *fd = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!name || !interface) {
|
||||
if ( !name || !interface )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
@ -426,20 +490,23 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
ntfsInit();
|
||||
|
||||
// Check that the requested mount name is free
|
||||
if (ntfsGetDevice(name, false)) {
|
||||
if ( ntfsGetDevice( name, false ) )
|
||||
{
|
||||
errno = EADDRINUSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we can at least read from this device
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANREAD)) {
|
||||
if ( !( interface->features & FEATURE_MEDIUM_CANREAD ) )
|
||||
{
|
||||
errno = EPERM;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the volume descriptor
|
||||
vd = ( ntfs_vd* )ntfs_alloc( sizeof( ntfs_vd ) );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@ -457,7 +524,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
|
||||
// Allocate the device driver descriptor
|
||||
fd = ( gekko_fd* )ntfs_alloc( sizeof( gekko_fd ) );
|
||||
if (!fd) {
|
||||
if ( !fd )
|
||||
{
|
||||
ntfs_free( vd );
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
@ -473,7 +541,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
|
||||
// Allocate the device driver
|
||||
vd->dev = ntfs_device_alloc( name, 0, &ntfs_device_gekko_io_ops, fd );
|
||||
if (!vd->dev) {
|
||||
if ( !vd->dev )
|
||||
{
|
||||
ntfs_free( fd );
|
||||
ntfs_free( vd );
|
||||
return false;
|
||||
@ -499,8 +568,10 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
|
||||
// Mount the device
|
||||
vd->vol = ntfs_device_mount( vd->dev, vd->flags );
|
||||
if (!vd->vol) {
|
||||
switch(ntfs_volume_error(errno)) {
|
||||
if ( !vd->vol )
|
||||
{
|
||||
switch ( ntfs_volume_error( errno ) )
|
||||
{
|
||||
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
||||
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
||||
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
||||
@ -513,14 +584,16 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
}
|
||||
|
||||
// Initialise the volume descriptor
|
||||
if (ntfsInitVolume(vd)) {
|
||||
if ( ntfsInitVolume( vd ) )
|
||||
{
|
||||
ntfs_umount( vd->vol, true );
|
||||
ntfs_free( vd );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the device to the devoptab table
|
||||
if (ntfsAddDevice(name, vd)) {
|
||||
if ( ntfsAddDevice( name, vd ) )
|
||||
{
|
||||
ntfsDeinitVolume( vd );
|
||||
ntfs_umount( vd->vol, true );
|
||||
ntfs_free( vd );
|
||||
@ -562,14 +635,16 @@ const char *ntfsGetVolumeName (const char *name)
|
||||
//char *volumeName = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!name) {
|
||||
if ( !name )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume( name );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
@ -642,14 +717,16 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
int ulabel_len;
|
||||
|
||||
// Sanity check
|
||||
if (!name) {
|
||||
if ( !name )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume( name );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return false;
|
||||
}
|
||||
@ -659,7 +736,8 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// Convert the new volume name to unicode
|
||||
ulabel_len = ntfsLocalToUnicode( volumeName, &ulabel ) * sizeof( ntfschar );
|
||||
if (ulabel_len < 0) {
|
||||
if ( ulabel_len < 0 )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
@ -667,26 +745,32 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// Check if the volume name attribute exists
|
||||
na = ntfs_attr_open( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
|
||||
// It does, resize it to match the length of the new volume name
|
||||
if (ntfs_attr_truncate(na, ulabel_len)) {
|
||||
if ( ntfs_attr_truncate( na, ulabel_len ) )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the new volume name
|
||||
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
|
||||
if ( ntfs_attr_pwrite( na, 0, ulabel_len, ulabel ) != ulabel_len )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// It doesn't, create it now
|
||||
if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) {
|
||||
if ( ntfs_attr_add( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, ( u8* )ulabel, ulabel_len ) )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
return false;
|
||||
@ -702,7 +786,8 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
ntfs_attr_close( na );
|
||||
|
||||
// Sync the volume node
|
||||
if (ntfs_inode_sync(vd->vol->vol_ni)) {
|
||||
if ( ntfs_inode_sync( vd->vol->vol_ni ) )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
return false;
|
||||
|
@ -23,7 +23,8 @@
|
||||
#define _LIBNTFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <gctypes.h>
|
||||
@ -54,7 +55,8 @@ extern "C" {
|
||||
/**
|
||||
* ntfs_md - NTFS mount descriptor
|
||||
*/
|
||||
typedef struct _ntfs_md {
|
||||
typedef struct _ntfs_md
|
||||
{
|
||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||
sec_t startSector; /* Local block address to first sector of partition */
|
||||
|
@ -54,7 +54,8 @@ void ntfsCloseDir (ntfs_dir_state *dir)
|
||||
return;
|
||||
|
||||
// Free the directory entries (if any)
|
||||
while (dir->first) {
|
||||
while ( dir->first )
|
||||
{
|
||||
ntfs_dir_entry *next = dir->first->next;
|
||||
ntfs_free( dir->first->name );
|
||||
ntfs_free( dir->first );
|
||||
@ -86,7 +87,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( path );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -103,7 +105,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry( vd, path );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
r->_errno = errno;
|
||||
ntfsUnlock( vd );
|
||||
return -1;
|
||||
@ -131,7 +134,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( existing );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -141,7 +145,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
|
||||
// Create a symbolic link between the two paths
|
||||
ni = ntfsCreate( vd, existing, S_IFLNK, newLink );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -177,7 +182,8 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( name );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -187,14 +193,16 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
|
||||
// Find the directory
|
||||
ni = ntfsOpenEntry( vd, name );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
if ( !( ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
ntfsCloseEntry( vd, ni );
|
||||
ntfsUnlock( vd );
|
||||
r->_errno = ENOTDIR;
|
||||
@ -223,7 +231,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( oldName );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -232,7 +241,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
ntfsLock( vd );
|
||||
|
||||
// You cannot rename between devices
|
||||
if(vd != ntfsGetVolume(newName)) {
|
||||
if ( vd != ntfsGetVolume( newName ) )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
@ -240,7 +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
|
||||
ni = ntfsOpenEntry( vd, newName );
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
ntfsCloseEntry( vd, ni );
|
||||
ntfsUnlock( vd );
|
||||
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
|
||||
if (ntfsLink(vd, oldName, newName)) {
|
||||
if ( ntfsLink( vd, oldName, newName ) )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unlink the old entry
|
||||
if (ntfsUnlink(vd, oldName)) {
|
||||
if (ntfsUnlink(vd, newName)) {
|
||||
if ( ntfsUnlink( vd, oldName ) )
|
||||
{
|
||||
if ( ntfsUnlink( vd, newName ) )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
return -1;
|
||||
}
|
||||
@ -278,7 +292,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( path );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -288,7 +303,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
|
||||
// Create the directory
|
||||
ni = ntfsCreate( vd, path, S_IFDIR, NULL );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -313,7 +329,8 @@ int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( path );
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -387,21 +404,25 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
char *entry_name = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd) {
|
||||
if ( !dir || !dir->vd )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ignore DOS file names
|
||||
if (name_type == FILE_NAME_DOS) {
|
||||
if ( name_type == FILE_NAME_DOS )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
|
||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles) {
|
||||
if ( MREF( mref ) == FILE_root || MREF( mref ) >= FILE_first_user || dir->vd->showSystemFiles )
|
||||
{
|
||||
|
||||
// Convert the entry name to our current local
|
||||
if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0) {
|
||||
if ( ntfsUnicodeToLocal( name, name_len, &entry_name, 0 ) < 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -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 ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0)) {
|
||||
if ( ( strcmp( entry_name, "." ) != 0 ) && ( strcmp( entry_name, ".." ) != 0 ) )
|
||||
{
|
||||
|
||||
// Open the entry
|
||||
ntfs_inode *ni = ntfs_pathname_to_inode( dir->vd->vol, dir->ni, entry_name );
|
||||
@ -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)
|
||||
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 );
|
||||
return 0;
|
||||
}
|
||||
@ -442,9 +465,12 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
entry->mref = MREF( mref );
|
||||
|
||||
// Link the entry to the directory
|
||||
if (!dir->first) {
|
||||
if ( !dir->first )
|
||||
{
|
||||
dir->first = entry;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_dir_entry *last = dir->first;
|
||||
while ( last->next ) last = last->next;
|
||||
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
|
||||
dir->vd = ntfsGetVolume( path );
|
||||
if (!dir->vd) {
|
||||
if ( !dir->vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
@ -474,14 +501,16 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
// Find the directory
|
||||
dir->ni = ntfsOpenEntry( dir->vd, path );
|
||||
if (!dir->ni) {
|
||||
if ( !dir->ni )
|
||||
{
|
||||
ntfsUnlock( dir->vd );
|
||||
r->_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
if ( !( dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
ntfsCloseEntry( dir->vd, dir->ni );
|
||||
ntfsUnlock( dir->vd );
|
||||
r->_errno = ENOTDIR;
|
||||
@ -490,7 +519,8 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
// Read the directory
|
||||
dir->first = dir->current = NULL;
|
||||
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
|
||||
if ( ntfs_readdir( dir->ni, &position, dirState, ( ntfs_filldir_t )ntfs_readdir_filler ) )
|
||||
{
|
||||
ntfsCloseDir( dir );
|
||||
ntfsUnlock( dir->vd );
|
||||
r->_errno = errno;
|
||||
@ -504,10 +534,13 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
||||
|
||||
// Insert the directory into the double-linked FILO list of open directories
|
||||
if (dir->vd->firstOpenDir) {
|
||||
if ( dir->vd->firstOpenDir )
|
||||
{
|
||||
dir->nextOpenDir = dir->vd->firstOpenDir;
|
||||
dir->vd->firstOpenDir->prevOpenDir = dir;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dir->nextOpenDir = NULL;
|
||||
}
|
||||
dir->prevOpenDir = NULL;
|
||||
@ -528,7 +561,8 @@ int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||
ntfs_dir_state* dir = STATE( dirState );
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
if ( !dir || !dir->vd || !dir->ni )
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -556,7 +590,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
if ( !dir || !dir->vd || !dir->ni )
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -565,7 +600,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
ntfsLock( dir->vd );
|
||||
|
||||
// Check that there is a entry waiting to be fetched
|
||||
if (!dir->current) {
|
||||
if ( !dir->current )
|
||||
{
|
||||
ntfsUnlock( dir->vd );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
@ -583,7 +619,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
else
|
||||
{
|
||||
ni = ntfsOpenEntry( dir->vd, dir->current->name );
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
ntfsStat( dir->vd, ni, filestat );
|
||||
ntfsCloseEntry( dir->vd, ni );
|
||||
}
|
||||
@ -609,7 +646,8 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
ntfs_dir_state* dir = STATE( dirState );
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd) {
|
||||
if ( !dir || !dir->vd )
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
@ -28,7 +28,8 @@
|
||||
/**
|
||||
* ntfs_dir_entry - Directory entry
|
||||
*/
|
||||
typedef struct _ntfs_dir_entry {
|
||||
typedef struct _ntfs_dir_entry
|
||||
{
|
||||
char *name;
|
||||
u64 mref;
|
||||
struct _ntfs_dir_entry *next;
|
||||
@ -37,7 +38,8 @@ typedef struct _ntfs_dir_entry {
|
||||
/**
|
||||
* ntfs_dir_state - Directory state
|
||||
*/
|
||||
typedef struct _ntfs_dir_state {
|
||||
typedef struct _ntfs_dir_state
|
||||
{
|
||||
ntfs_vd *vd; /* Volume this directory belongs to */
|
||||
ntfs_inode *ni; /* Directory descriptor */
|
||||
ntfs_dir_entry *first; /* The first entry in the directory */
|
||||
|
@ -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
|
||||
file->vd = ntfsGetVolume( path );
|
||||
if (!file->vd) {
|
||||
if ( !file->vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
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
|
||||
file->flags = flags;
|
||||
if ((flags & 0x03) == O_RDONLY) {
|
||||
if ( ( flags & 0x03 ) == O_RDONLY )
|
||||
{
|
||||
file->read = true;
|
||||
file->write = false;
|
||||
file->append = false;
|
||||
} else if ((flags & 0x03) == O_WRONLY) {
|
||||
}
|
||||
else if ( ( flags & 0x03 ) == O_WRONLY )
|
||||
{
|
||||
file->read = false;
|
||||
file->write = true;
|
||||
file->append = ( flags & O_APPEND );
|
||||
} else if ((flags & 0x03) == O_RDWR) {
|
||||
}
|
||||
else if ( ( flags & 0x03 ) == O_RDWR )
|
||||
{
|
||||
file->read = true;
|
||||
file->write = true;
|
||||
file->append = ( flags & O_APPEND );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
r->_errno = EACCES;
|
||||
ntfsUnlock( file->vd );
|
||||
return -1;
|
||||
@ -127,7 +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
|
||||
file->ni = ntfsOpenEntry( file->vd, path );
|
||||
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
if ( file->ni && ( file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EISDIR;
|
||||
@ -135,10 +144,12 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Are we creating this file?
|
||||
if (flags & O_CREAT) {
|
||||
if ( flags & O_CREAT )
|
||||
{
|
||||
|
||||
// The file SHOULD NOT already exist
|
||||
if (file->ni) {
|
||||
if ( file->ni )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EEXIST;
|
||||
@ -147,7 +158,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
|
||||
// Create the file
|
||||
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
||||
if (!file->ni) {
|
||||
if ( !file->ni )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
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
|
||||
if (!file->ni) {
|
||||
if ( !file->ni )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = ENOENT;
|
||||
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
|
||||
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
||||
if(!file->data_na) {
|
||||
if ( !file->data_na )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
return -1;
|
||||
@ -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 );
|
||||
|
||||
// We cannot read/write encrypted files
|
||||
if (file->encrypted) {
|
||||
if ( file->encrypted )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
@ -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
|
||||
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
|
||||
if ( ( file->ni->flags & FILE_ATTR_READONLY ) && file->write )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
@ -192,8 +208,10 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Truncate the file if requested
|
||||
if ((flags & O_TRUNC) && file->write) {
|
||||
if (ntfs_attr_truncate(file->data_na, 0)) {
|
||||
if ( ( flags & O_TRUNC ) && file->write )
|
||||
{
|
||||
if ( ntfs_attr_truncate( file->data_na, 0 ) )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
@ -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 );
|
||||
|
||||
// Insert the file into the double-linked FILO list of open files
|
||||
if (file->vd->firstOpenFile) {
|
||||
if ( file->vd->firstOpenFile )
|
||||
{
|
||||
file->nextOpenFile = file->vd->firstOpenFile;
|
||||
file->vd->firstOpenFile->prevOpenFile = file;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
file->nextOpenFile = NULL;
|
||||
}
|
||||
file->prevOpenFile = NULL;
|
||||
@ -235,7 +256,8 @@ int ntfs_close_r (struct _reent *r, int fd)
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd) {
|
||||
if ( !file || !file->vd )
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases where we don't actually have to do anything
|
||||
if (!ptr || len <= 0) {
|
||||
if ( !ptr || len <= 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -284,22 +308,26 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||
ntfsLock( file->vd );
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if (!file->write) {
|
||||
if ( !file->write )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we are in append mode, backup the current position and move to the end of the file
|
||||
if (file->append) {
|
||||
if ( file->append )
|
||||
{
|
||||
old_pos = file->pos;
|
||||
file->pos = file->len;
|
||||
}
|
||||
|
||||
// Write to the files data atrribute
|
||||
while (len) {
|
||||
while ( len )
|
||||
{
|
||||
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
||||
if (ret <= 0) {
|
||||
if ( ret <= 0 )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -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 (file->append) {
|
||||
if ( file->append )
|
||||
{
|
||||
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;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases where we don't actually have to do anything
|
||||
if (!ptr || len <= 0) {
|
||||
if ( !ptr || len <= 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -349,14 +380,16 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||
ntfsLock( file->vd );
|
||||
|
||||
// Check that we are allowed to read from this file
|
||||
if (!file->read) {
|
||||
if ( !file->read )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Don't read past the end of file
|
||||
if (file->pos + len > file->len) {
|
||||
if ( file->pos + len > file->len )
|
||||
{
|
||||
r->_errno = EOVERFLOW;
|
||||
len = file->len - file->pos;
|
||||
ntfs_log_trace( "EOVERFLOW" );
|
||||
@ -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 );
|
||||
|
||||
// Read from the files data attribute
|
||||
while (len) {
|
||||
while ( len )
|
||||
{
|
||||
ssize_t ret = ntfs_attr_pread( file->data_na, file->pos, len, ptr );
|
||||
if (ret <= 0 || ret > len) {
|
||||
if ( ret <= 0 || ret > len )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -394,7 +429,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||
off_t position = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -403,7 +439,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||
ntfsLock( file->vd );
|
||||
|
||||
// Set the files current position
|
||||
switch(dir) {
|
||||
switch ( dir )
|
||||
{
|
||||
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break;
|
||||
case SEEK_CUR: position = file->pos = MIN( MAX( file->pos + pos, 0 ), file->len ); break;
|
||||
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
||||
@ -422,7 +459,8 @@ int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -446,7 +484,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -455,7 +494,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
ntfsLock( file->vd );
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if (!file->write) {
|
||||
if ( !file->write )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
@ -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
|
||||
if ( file->compressed &&
|
||||
len > 0 &&
|
||||
len < file->data_na->initialized_size) {
|
||||
len < file->data_na->initialized_size )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Resize the files data attribute, either by expanding or truncating
|
||||
if (file->compressed && len > file->data_na->initialized_size) {
|
||||
if ( file->compressed && len > file->data_na->initialized_size )
|
||||
{
|
||||
char zero = 0;
|
||||
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
|
||||
if ( ntfs_attr_pwrite( file->data_na, len - 1, 1, &zero ) <= 0 )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (ntfs_attr_truncate(file->data_na, len)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ntfs_attr_truncate( file->data_na, len ) )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -514,7 +560,8 @@ int ntfs_fsync_r (struct _reent *r, int fd)
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
@ -32,7 +32,8 @@
|
||||
/**
|
||||
* ntfs_file_state - File state
|
||||
*/
|
||||
typedef struct _ntfs_file_state {
|
||||
typedef struct _ntfs_file_state
|
||||
{
|
||||
ntfs_vd *vd; /* Volume this file belongs to */
|
||||
ntfs_inode *ni; /* File descriptor */
|
||||
ntfs_attr *data_na; /* File data descriptor */
|
||||
|
@ -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
|
||||
file->vd = ntfsGetVolume( path );
|
||||
if (!file->vd) {
|
||||
if ( !file->vd )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
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
|
||||
file->flags = flags;
|
||||
if ((flags & 0x03) == O_RDONLY) {
|
||||
if ( ( flags & 0x03 ) == O_RDONLY )
|
||||
{
|
||||
file->read = true;
|
||||
file->write = false;
|
||||
file->append = false;
|
||||
} else if ((flags & 0x03) == O_WRONLY) {
|
||||
}
|
||||
else if ( ( flags & 0x03 ) == O_WRONLY )
|
||||
{
|
||||
file->read = false;
|
||||
file->write = true;
|
||||
file->append = ( flags & O_APPEND );
|
||||
} else if ((flags & 0x03) == O_RDWR) {
|
||||
}
|
||||
else if ( ( flags & 0x03 ) == O_RDWR )
|
||||
{
|
||||
file->read = true;
|
||||
file->write = true;
|
||||
file->append = ( flags & O_APPEND );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
r->_errno = EACCES;
|
||||
ntfsUnlock( file->vd );
|
||||
return -1;
|
||||
@ -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
|
||||
file->ni = ntfsOpenEntry( file->vd, path );
|
||||
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
if ( file->ni && ( file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EISDIR;
|
||||
@ -140,10 +149,12 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Are we creating this file?
|
||||
if (flags & O_CREAT) {
|
||||
if ( flags & O_CREAT )
|
||||
{
|
||||
|
||||
// The file SHOULD NOT already exist
|
||||
if (file->ni) {
|
||||
if ( file->ni )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EEXIST;
|
||||
@ -152,7 +163,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
|
||||
// Create the file
|
||||
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
||||
if (!file->ni) {
|
||||
if ( !file->ni )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
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
|
||||
if (!file->ni) {
|
||||
if ( !file->ni )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = ENOENT;
|
||||
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
|
||||
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
||||
if(!file->data_na) {
|
||||
if ( !file->data_na )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
return -1;
|
||||
@ -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 );
|
||||
|
||||
// We cannot read/write encrypted files
|
||||
if (file->encrypted) {
|
||||
if ( file->encrypted )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
@ -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
|
||||
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
|
||||
if ( ( file->ni->flags & FILE_ATTR_READONLY ) && file->write )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
@ -197,8 +213,10 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Truncate the file if requested
|
||||
if ((flags & O_TRUNC) && file->write) {
|
||||
if (ntfs_attr_truncate(file->data_na, 0)) {
|
||||
if ( ( flags & O_TRUNC ) && file->write )
|
||||
{
|
||||
if ( ntfs_attr_truncate( file->data_na, 0 ) )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
@ -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 );
|
||||
|
||||
// Insert the file into the double-linked FILO list of open files
|
||||
if (file->vd->firstOpenFile) {
|
||||
if ( file->vd->firstOpenFile )
|
||||
{
|
||||
file->nextOpenFile = file->vd->firstOpenFile;
|
||||
file->vd->firstOpenFile->prevOpenFile = file;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
file->nextOpenFile = NULL;
|
||||
}
|
||||
file->prevOpenFile = NULL;
|
||||
@ -240,7 +261,8 @@ int ntfs_close_r (struct _reent *r, int fd)
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd) {
|
||||
if ( !file || !file->vd )
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases where we don't actually have to do anything
|
||||
if (!ptr || len <= 0) {
|
||||
if ( !ptr || len <= 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -289,22 +313,26 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||
ntfsLock( file->vd );
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if (!file->write) {
|
||||
if ( !file->write )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we are in append mode, backup the current position and move to the end of the file
|
||||
if (file->append) {
|
||||
if ( file->append )
|
||||
{
|
||||
old_pos = file->pos;
|
||||
file->pos = file->len;
|
||||
}
|
||||
|
||||
// Write to the files data atrribute
|
||||
while (len) {
|
||||
while ( len )
|
||||
{
|
||||
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
||||
if (ret <= 0) {
|
||||
if ( ret <= 0 )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -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 (file->append) {
|
||||
if ( file->append )
|
||||
{
|
||||
file->pos = old_pos;
|
||||
}
|
||||
|
||||
@ -355,7 +384,8 @@ int _NTFS_get_fragments (const char *path,
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
//r->_errno = EINVAL;
|
||||
return -13;
|
||||
}
|
||||
@ -389,10 +419,12 @@ int _NTFS_get_fragments (const char *path,
|
||||
u64 len = file->len;
|
||||
|
||||
// Read from the files data attribute
|
||||
while (len) {
|
||||
while ( len )
|
||||
{
|
||||
s64 ret = ntfs_attr_getfragments( file->data_na, file->pos,
|
||||
len, offset, append_fragment, callback_data );
|
||||
if (ret <= 0 || ret > len) {
|
||||
if ( ret <= 0 || ret > len )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
//r->_errno = errno;
|
||||
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;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -445,7 +478,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||
ntfsLock( file->vd );
|
||||
|
||||
// Set the files current position
|
||||
switch(dir) {
|
||||
switch ( dir )
|
||||
{
|
||||
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break;
|
||||
case SEEK_CUR: position = file->pos = MIN( MAX( file->pos + pos, 0 ), file->len ); break;
|
||||
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
||||
@ -464,7 +498,8 @@ int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -488,7 +523,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -497,7 +533,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
ntfsLock( file->vd );
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if (!file->write) {
|
||||
if ( !file->write )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
@ -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
|
||||
if ( file->compressed &&
|
||||
len > 0 &&
|
||||
len < file->data_na->initialized_size) {
|
||||
len < file->data_na->initialized_size )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Resize the files data attribute, either by expanding or truncating
|
||||
if (file->compressed && len > file->data_na->initialized_size) {
|
||||
if ( file->compressed && len > file->data_na->initialized_size )
|
||||
{
|
||||
char zero = 0;
|
||||
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
|
||||
if ( ntfs_attr_pwrite( file->data_na, len - 1, 1, &zero ) <= 0 )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (ntfs_attr_truncate(file->data_na, len)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ntfs_attr_truncate( file->data_na, len ) )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -556,7 +599,8 @@ int ntfs_fsync_r (struct _reent *r, int fd)
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
@ -43,7 +43,8 @@
|
||||
#include <sdcard/gcsd.h>
|
||||
#include <ogc/usbstorage.h>
|
||||
|
||||
const INTERFACE_ID ntfs_disc_interfaces[] = {
|
||||
const INTERFACE_ID ntfs_disc_interfaces[] =
|
||||
{
|
||||
{ "sd", &__io_wiisd },
|
||||
{ "usb", &__io_usbstorage },
|
||||
{ "carda", &__io_gcsda },
|
||||
@ -54,7 +55,8 @@ const INTERFACE_ID ntfs_disc_interfaces[] = {
|
||||
#elif defined(__gamecube__)
|
||||
#include <sdcard/gcsd.h>
|
||||
|
||||
const INTERFACE_ID ntfs_disc_interfaces[] = {
|
||||
const INTERFACE_ID ntfs_disc_interfaces[] =
|
||||
{
|
||||
{ "carda", &__io_gcsda },
|
||||
{ "cardb", &__io_gcsdb },
|
||||
{ NULL, NULL }
|
||||
@ -70,14 +72,16 @@ int ntfsAddDevice (const char *name, void *deviceData)
|
||||
int i;
|
||||
|
||||
// Sanity check
|
||||
if (!name || !deviceData || !devoptab_ntfs) {
|
||||
if ( !name || !deviceData || !devoptab_ntfs )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allocate a devoptab for this device
|
||||
dev = ( devoptab_t * ) ntfs_alloc( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@ -92,8 +96,10 @@ int ntfsAddDevice (const char *name, void *deviceData)
|
||||
dev->deviceData = deviceData;
|
||||
|
||||
// Add the device to the devoptab table (if there is a free slot)
|
||||
for (i = 0; i < STD_MAX; i++) {
|
||||
if (devoptab_list[i] == devoptab_list[0] && i != 0) {
|
||||
for ( i = 0; i < STD_MAX; i++ )
|
||||
{
|
||||
if ( devoptab_list[i] == devoptab_list[0] && i != 0 )
|
||||
{
|
||||
devoptab_list[i] = dev;
|
||||
return 0;
|
||||
}
|
||||
@ -118,10 +124,13 @@ void ntfsRemoveDevice (const char *path)
|
||||
// NOTE: We do this manually due to a 'bug' in RemoveDevice
|
||||
// which ignores names with suffixes and causes names
|
||||
// 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];
|
||||
if (devoptab && devoptab->name) {
|
||||
if (strcmp(name, devoptab->name) == 0) {
|
||||
if ( devoptab && devoptab->name )
|
||||
{
|
||||
if ( strcmp( name, devoptab->name ) == 0 )
|
||||
{
|
||||
devoptab_list[i] = devoptab_list[0];
|
||||
ntfs_free( ( devoptab_t* )devoptab );
|
||||
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
|
||||
// which ignores names with suffixes and causes names
|
||||
// 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];
|
||||
if (devoptab && devoptab->name) {
|
||||
if (strcmp(name, devoptab->name) == 0) {
|
||||
if ( devoptab && devoptab->name )
|
||||
{
|
||||
if ( strcmp( name, devoptab->name ) == 0 )
|
||||
{
|
||||
return devoptab;
|
||||
}
|
||||
}
|
||||
@ -184,7 +196,8 @@ ntfs_vd *ntfsGetVolume (const char *path)
|
||||
int ntfsInitVolume ( ntfs_vd *vd )
|
||||
{
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -210,7 +223,8 @@ int ntfsInitVolume (ntfs_vd *vd)
|
||||
void ntfsDeinitVolume ( ntfs_vd *vd )
|
||||
{
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return;
|
||||
}
|
||||
@ -220,7 +234,8 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
||||
|
||||
// Close any directories which are still open (lazy programmers!)
|
||||
ntfs_dir_state *nextDir = vd->firstOpenDir;
|
||||
while (nextDir) {
|
||||
while ( nextDir )
|
||||
{
|
||||
ntfs_log_warning( "Cleaning up orphaned directory @ %p\n", nextDir );
|
||||
ntfsCloseDir( nextDir );
|
||||
nextDir = nextDir->nextOpenDir;
|
||||
@ -228,7 +243,8 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
||||
|
||||
// Close any files which are still open (lazy programmers!)
|
||||
ntfs_file_state *nextFile = vd->firstOpenFile;
|
||||
while (nextFile) {
|
||||
while ( nextFile )
|
||||
{
|
||||
ntfs_log_warning( "Cleaning up orphaned file @ %p\n", nextFile );
|
||||
ntfsCloseFile( nextFile );
|
||||
nextFile = nextFile->nextOpenFile;
|
||||
@ -270,17 +286,21 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
||||
int attr_size;
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the actual path of the entry
|
||||
path = ntfsRealPath( path );
|
||||
if (!path) {
|
||||
if ( !path )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
} else if (path[0] == '\0') {
|
||||
}
|
||||
else if ( path[0] == '\0' )
|
||||
{
|
||||
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;
|
||||
// this resolves the true location of symbolic links and directory junctions
|
||||
if (ni && (ni->flags & FILE_ATTR_REPARSE_POINT)) {
|
||||
if (ntfs_possible_symlink(ni)) {
|
||||
if ( ni && ( ni->flags & FILE_ATTR_REPARSE_POINT ) )
|
||||
{
|
||||
if ( ntfs_possible_symlink( ni ) )
|
||||
{
|
||||
|
||||
// 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 );
|
||||
errno = ELOOP;
|
||||
return NULL;
|
||||
@ -304,7 +327,8 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
||||
|
||||
// Get the target path of this entry
|
||||
target = ntfs_make_symlink( ni, path, &attr_size );
|
||||
if (!target) {
|
||||
if ( !target )
|
||||
{
|
||||
ntfsCloseEntry( vd, ni );
|
||||
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 )
|
||||
{
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return;
|
||||
}
|
||||
@ -358,14 +383,17 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
int uname_len, utarget_len;
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// You cannot link between devices
|
||||
if(target) {
|
||||
if(vd != ntfsGetVolume(target)) {
|
||||
if ( target )
|
||||
{
|
||||
if ( vd != ntfsGetVolume( target ) )
|
||||
{
|
||||
errno = EXDEV;
|
||||
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
|
||||
path = ntfsRealPath( path );
|
||||
target = ntfsRealPath( target );
|
||||
if (!path) {
|
||||
if ( !path )
|
||||
{
|
||||
errno = EINVAL;
|
||||
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
|
||||
// TODO: This looks horrible, clean it up
|
||||
dir = strdup( path );
|
||||
if (!dir) {
|
||||
if ( !dir )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -395,7 +425,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
else
|
||||
name = dir;
|
||||
uname_len = ntfsLocalToUnicode( name, &uname );
|
||||
if (uname_len < 0) {
|
||||
if ( uname_len < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
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
|
||||
dir_ni = ntfsOpenEntry( vd, dir );
|
||||
if (!dir_ni) {
|
||||
if ( !dir_ni )
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Create the entry
|
||||
switch (type) {
|
||||
switch ( type )
|
||||
{
|
||||
|
||||
// Symbolic link
|
||||
case S_IFLNK:
|
||||
if (!target) {
|
||||
if ( !target )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
utarget_len = ntfsLocalToUnicode( target, &utarget );
|
||||
if (utarget_len < 0) {
|
||||
if ( utarget_len < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
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 (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
|
||||
// Mark the entry for archiving
|
||||
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;
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// You cannot link between devices
|
||||
if(vd != ntfsGetVolume(new_path)) {
|
||||
if ( vd != ntfsGetVolume( new_path ) )
|
||||
{
|
||||
errno = EXDEV;
|
||||
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
|
||||
old_path = ntfsRealPath( old_path );
|
||||
new_path = ntfsRealPath( new_path );
|
||||
if (!old_path || !new_path) {
|
||||
if ( !old_path || !new_path )
|
||||
{
|
||||
errno = EINVAL;
|
||||
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
|
||||
// TODO: This looks horrible, clean it up
|
||||
dir = strdup( new_path );
|
||||
if (!dir) {
|
||||
if ( !dir )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -519,7 +559,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
||||
else
|
||||
name = dir;
|
||||
uname_len = ntfsLocalToUnicode( name, &uname );
|
||||
if (uname_len < 0) {
|
||||
if ( uname_len < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -527,7 +568,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry( vd, old_path );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
errno = ENOENT;
|
||||
res = -1;
|
||||
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
|
||||
dir_ni = ntfsOpenEntry( vd, dir );
|
||||
if (!dir_ni) {
|
||||
if ( !dir_ni )
|
||||
{
|
||||
errno = ENOENT;
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// 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;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -583,14 +627,16 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
int res = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the actual path of the entry
|
||||
path = ntfsRealPath( path );
|
||||
if (!path) {
|
||||
if ( !path )
|
||||
{
|
||||
errno = EINVAL;
|
||||
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
|
||||
// TODO: This looks horrible
|
||||
dir = strdup( path );
|
||||
if (!dir) {
|
||||
if ( !dir )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -611,7 +658,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
else
|
||||
name = dir;
|
||||
uname_len = ntfsLocalToUnicode( name, &uname );
|
||||
if (uname_len < 0) {
|
||||
if ( uname_len < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -624,7 +672,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry( vd, path );
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
errno = ENOENT;
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
@ -632,14 +681,16 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
|
||||
// Open the entries parent directory
|
||||
dir_ni = ntfsOpenEntry( vd, dir );
|
||||
if (!dir_ni) {
|
||||
if ( !dir_ni )
|
||||
{
|
||||
errno = ENOENT;
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -674,13 +725,15 @@ int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)
|
||||
int res = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
@ -707,13 +760,15 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
||||
int res = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
if ( !vd )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (!ni) {
|
||||
if ( !ni )
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
@ -729,20 +784,24 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
||||
memset( st, 0, sizeof( struct stat ) );
|
||||
|
||||
// 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_nlink = 1;
|
||||
|
||||
// Open the directories index allocation table attribute
|
||||
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
st->st_size = na->data_size;
|
||||
st->st_blocks = na->allocated_size >> 9;
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
|
||||
// Else it must be a file
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
st->st_mode = S_IFREG | ( 0777 & ~vd->fmask );
|
||||
st->st_size = ni->data_size;
|
||||
st->st_blocks = ( ni->allocated_size + 511 ) >> 9;
|
||||
@ -787,10 +846,12 @@ const char *ntfsRealPath (const char *path)
|
||||
return NULL;
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr(path, ':') != NULL) {
|
||||
if ( strchr( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr(path, ':') != NULL) {
|
||||
if ( strchr( path, ':' ) != 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
|
||||
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,
|
||||
// do it manually by replacing non-ASCII characters with underscores
|
||||
if (!*outs || outs_len >= ins_len) {
|
||||
if (!*outs) {
|
||||
if ( !*outs || outs_len >= ins_len )
|
||||
{
|
||||
if ( !*outs )
|
||||
{
|
||||
*outs = ( char * ) ntfs_alloc( ins_len + 1 );
|
||||
if (!*outs) {
|
||||
if ( !*outs )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ins_len; i++) {
|
||||
for ( i = 0; i < ins_len; i++ )
|
||||
{
|
||||
ntfschar uc = le16_to_cpu( ins[i] );
|
||||
if ( uc > 0xff )
|
||||
uc = ( ntfschar )'_';
|
||||
|
@ -69,7 +69,8 @@ struct _ntfs_dir_state;
|
||||
/**
|
||||
* PRIMARY_PARTITION - Block device partition record
|
||||
*/
|
||||
typedef struct _PARTITION_RECORD {
|
||||
typedef struct _PARTITION_RECORD
|
||||
{
|
||||
u8 status; /* Partition status; see above */
|
||||
u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */
|
||||
u8 type; /* Partition type; see above */
|
||||
@ -81,7 +82,8 @@ typedef struct _PARTITION_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 */
|
||||
PARTITION_RECORD partitions[4]; /* 4 primary partitions */
|
||||
u16 signature; /* MBR signature; 0xAA55 */
|
||||
@ -90,7 +92,8 @@ typedef struct _MASTER_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 */
|
||||
PARTITION_RECORD partition; /* Primary partition */
|
||||
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
|
||||
*/
|
||||
typedef struct _INTERFACE_ID {
|
||||
typedef struct _INTERFACE_ID
|
||||
{
|
||||
const char *name; /* Interface name */
|
||||
const DISC_INTERFACE *interface; /* Disc interface */
|
||||
} INTERFACE_ID;
|
||||
@ -109,7 +113,8 @@ typedef struct _INTERFACE_ID {
|
||||
/**
|
||||
* ntfs_atime_t - File access time update strategies
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ATIME_ENABLED, /* Update access times */
|
||||
ATIME_DISABLED /* Don't update access times */
|
||||
} ntfs_atime_t;
|
||||
@ -117,7 +122,8 @@ typedef enum {
|
||||
/**
|
||||
* ntfs_vd - NTFS volume descriptor
|
||||
*/
|
||||
typedef struct _ntfs_vd {
|
||||
typedef struct _ntfs_vd
|
||||
{
|
||||
struct ntfs_device *dev; /* NTFS device handle */
|
||||
ntfs_volume *vol; /* NTFS volume handle */
|
||||
mutex_t lock; /* Volume lock mutex */
|
||||
|
@ -106,25 +106,29 @@
|
||||
* ---------------------- end from RFC 4122 -----------------------
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
GUID object_id;
|
||||
} OBJECT_ID_INDEX_KEY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
le64 file_id;
|
||||
GUID birth_volume_id;
|
||||
GUID birth_object_id;
|
||||
GUID domain_id;
|
||||
} 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;
|
||||
OBJECT_ID_INDEX_KEY key;
|
||||
OBJECT_ID_INDEX_DATA data;
|
||||
} ;
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
@ -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 */
|
||||
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
||||
ni = ( ntfs_inode* )NULL;
|
||||
if (dir_ni) {
|
||||
if ( dir_ni )
|
||||
{
|
||||
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$ObjId" );
|
||||
if ( inum != ( u64 ) - 1 )
|
||||
ni = ntfs_inode_open( vol, inum );
|
||||
ntfs_inode_close( dir_ni );
|
||||
}
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
xo = ntfs_index_ctx_get( ni, objid_index_name, 2 );
|
||||
if (!xo) {
|
||||
if ( !xo )
|
||||
{
|
||||
ntfs_inode_close( ni );
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
xo = ( ntfs_index_context* )NULL;
|
||||
return ( xo );
|
||||
}
|
||||
@ -230,15 +238,18 @@ static int merge_index_data(ntfs_inode *ni,
|
||||
|
||||
res = -1;
|
||||
xo = open_object_id_index( ni->vol );
|
||||
if (xo) {
|
||||
if ( xo )
|
||||
{
|
||||
memcpy( &key.object_id, objectid_attr, sizeof( GUID ) );
|
||||
if ( !ntfs_index_lookup( &key,
|
||||
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
||||
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
||||
{
|
||||
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
||||
/* make sure inode numbers match */
|
||||
if ( entry
|
||||
&& ( MREF( le64_to_cpu( entry->data.file_id ) )
|
||||
== ni->mft_no)) {
|
||||
== ni->mft_no ) )
|
||||
{
|
||||
memcpy( &full_objectid->birth_volume_id,
|
||||
&entry->data.birth_volume_id,
|
||||
sizeof( GUID ) );
|
||||
@ -277,15 +288,18 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
|
||||
int ret;
|
||||
|
||||
ret = na->data_size;
|
||||
if (ret) {
|
||||
if ( ret )
|
||||
{
|
||||
/* read the existing object id attribute */
|
||||
size = ntfs_attr_pread( na, 0, sizeof( GUID ), old_attr );
|
||||
if (size >= (s64)sizeof(GUID)) {
|
||||
if ( size >= ( s64 )sizeof( GUID ) )
|
||||
{
|
||||
memcpy( &key.object_id,
|
||||
&old_attr->object_id, sizeof( GUID ) );
|
||||
size = sizeof( GUID );
|
||||
if ( !ntfs_index_lookup( &key,
|
||||
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
||||
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
||||
{
|
||||
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
||||
memcpy( &old_attr->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 ) )
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -1;
|
||||
errno = ENODATA;
|
||||
}
|
||||
@ -335,21 +351,25 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
|
||||
res = 0;
|
||||
|
||||
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
|
||||
/* remove the existing index entry */
|
||||
oldsize = remove_object_id_index( na, xo, &old_attr );
|
||||
if ( oldsize < 0 )
|
||||
res = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate( na, ( s64 )sizeof( GUID ) );
|
||||
/* write the object_id in attribute */
|
||||
if (!res && value) {
|
||||
if ( !res && value )
|
||||
{
|
||||
written = ( int )ntfs_attr_pwrite( na,
|
||||
( s64 )0, ( s64 )sizeof( GUID ),
|
||||
&value->object_id );
|
||||
if (written != (s64)sizeof(GUID)) {
|
||||
if ( written != ( s64 )sizeof( GUID ) )
|
||||
{
|
||||
ntfs_log_error( "Failed to update "
|
||||
"object id\n" );
|
||||
errno = EIO;
|
||||
@ -359,7 +379,8 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
|
||||
/* write index part if provided */
|
||||
if ( !res
|
||||
&& ( ( 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
|
||||
* 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 );
|
||||
NInoSetDirty( ni );
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = -1;
|
||||
return ( res );
|
||||
}
|
||||
@ -390,22 +412,29 @@ static int add_object_id(ntfs_inode *ni, int flags)
|
||||
u8 dummy;
|
||||
|
||||
res = -1; /* default return */
|
||||
if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
if ( !ntfs_attr_exist( ni, AT_OBJECT_ID, AT_UNNAMED, 0 ) )
|
||||
{
|
||||
if ( !( flags & XATTR_REPLACE ) )
|
||||
{
|
||||
/*
|
||||
* no object id attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
* 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,
|
||||
AT_UNNAMED, 0, &dummy, ( s64 )0 );
|
||||
NInoSetDirty( ni );
|
||||
} else
|
||||
}
|
||||
else
|
||||
errno = EOPNOTSUPP;
|
||||
} else
|
||||
}
|
||||
else
|
||||
errno = ENODATA;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( flags & XATTR_CREATE )
|
||||
errno = EEXIST;
|
||||
else
|
||||
@ -433,13 +462,15 @@ int ntfs_delete_object_id_index(ntfs_inode *ni)
|
||||
|
||||
res = 0;
|
||||
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
/*
|
||||
* read the existing object id
|
||||
* and un-index it
|
||||
*/
|
||||
xo = open_object_id_index( ni->vol );
|
||||
if (xo) {
|
||||
if ( xo )
|
||||
{
|
||||
if ( remove_object_id_index( na, xo, &old_attr ) < 0 )
|
||||
res = -1;
|
||||
xoni = xo->ni;
|
||||
@ -473,34 +504,42 @@ int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size)
|
||||
int full_size;
|
||||
|
||||
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,
|
||||
AT_OBJECT_ID, ( ntfschar* )NULL, 0, &attr_size );
|
||||
if (objectid_attr) {
|
||||
if ( objectid_attr )
|
||||
{
|
||||
/* restrict to only GUID present in attr */
|
||||
if (attr_size == sizeof(GUID)) {
|
||||
if ( attr_size == sizeof( GUID ) )
|
||||
{
|
||||
memcpy( &full_objectid.object_id,
|
||||
objectid_attr, sizeof( GUID ) );
|
||||
full_size = sizeof( GUID );
|
||||
/* get data from index, if any */
|
||||
if ( !merge_index_data( ni, objectid_attr,
|
||||
&full_objectid)) {
|
||||
&full_objectid ) )
|
||||
{
|
||||
full_size = sizeof( OBJECT_ID_ATTR );
|
||||
}
|
||||
if (full_size <= (s64)size) {
|
||||
if ( full_size <= ( s64 )size )
|
||||
{
|
||||
if ( value )
|
||||
memcpy( value, &full_objectid,
|
||||
full_size );
|
||||
else
|
||||
errno = EINVAL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unexpected size, better return unsupported */
|
||||
errno = EOPNOTSUPP;
|
||||
full_size = 0;
|
||||
}
|
||||
free( objectid_attr );
|
||||
} else
|
||||
}
|
||||
else
|
||||
errno = ENODATA;
|
||||
}
|
||||
return ( full_size ? ( int )full_size : -errno );
|
||||
@ -525,22 +564,28 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni,
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
if (ni && value && (size >= sizeof(GUID))) {
|
||||
if ( ni && value && ( size >= sizeof( GUID ) ) )
|
||||
{
|
||||
xo = open_object_id_index( ni->vol );
|
||||
if (xo) {
|
||||
if ( xo )
|
||||
{
|
||||
/* make sure the GUID was not used somewhere */
|
||||
memcpy( &key.object_id, value, sizeof( GUID ) );
|
||||
if ( ntfs_index_lookup( &key,
|
||||
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
||||
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
||||
{
|
||||
ntfs_index_ctx_reinit( xo );
|
||||
res = add_object_id( ni, flags );
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
/* update value and index */
|
||||
res = update_object_id( ni, xo,
|
||||
( const OBJECT_ID_ATTR* )value,
|
||||
size );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* GUID is present elsewhere */
|
||||
res = -1;
|
||||
errno = EEXIST;
|
||||
@ -550,10 +595,14 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni,
|
||||
NInoSetDirty( xoni );
|
||||
ntfs_index_ctx_put( xo );
|
||||
ntfs_inode_close( xoni );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
@ -577,25 +626,32 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
|
||||
OBJECT_ID_ATTR old_attr;
|
||||
|
||||
res = 0;
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
/*
|
||||
* open and delete the object id
|
||||
*/
|
||||
na = ntfs_attr_open( ni, AT_OBJECT_ID,
|
||||
AT_UNNAMED, 0 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
/* first remove index (old object id needed) */
|
||||
xo = open_object_id_index( ni->vol );
|
||||
if (xo) {
|
||||
if ( xo )
|
||||
{
|
||||
oldsize = remove_object_id_index( na, xo,
|
||||
&old_attr );
|
||||
if (oldsize < 0) {
|
||||
if ( oldsize < 0 )
|
||||
{
|
||||
res = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* now remove attribute */
|
||||
res = ntfs_attr_rm( na );
|
||||
if ( res
|
||||
&& (oldsize > (int)sizeof(GUID))) {
|
||||
&& ( oldsize > ( int )sizeof( GUID ) ) )
|
||||
{
|
||||
/*
|
||||
* If we could not remove the
|
||||
* attribute, try to restore the
|
||||
@ -622,12 +678,16 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
|
||||
/* avoid errno pollution */
|
||||
if ( errno == ENOENT )
|
||||
errno = olderrno;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
NInoSetDirty( ni );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
|
@ -32,7 +32,8 @@
|
||||
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
|
||||
|
||||
/* default security sub-authorities */
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
||||
DEFSECAUTH2 = 589793238,
|
||||
DEFSECAUTH3 = 462843383,
|
||||
|
@ -71,7 +71,8 @@
|
||||
#define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007)
|
||||
#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_length;
|
||||
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 */
|
||||
} ;
|
||||
|
||||
struct SYMLINK_REPARSE_DATA { /* reparse data for symlinks */
|
||||
struct SYMLINK_REPARSE_DATA /* reparse data for symlinks */
|
||||
{
|
||||
le16 subst_name_offset;
|
||||
le16 subst_name_length;
|
||||
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 */
|
||||
} ;
|
||||
|
||||
struct REPARSE_INDEX { /* index entry in $Extend/$Reparse */
|
||||
struct REPARSE_INDEX /* index entry in $Extend/$Reparse */
|
||||
{
|
||||
INDEX_ENTRY_HEADER header;
|
||||
REPARSE_INDEX_KEY key;
|
||||
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( '\\' )
|
||||
} ;
|
||||
|
||||
static const ntfschar vol_junction_head[] = {
|
||||
static const ntfschar vol_junction_head[] =
|
||||
{
|
||||
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( '$' ),
|
||||
const_cpu_to_le16('R') };
|
||||
const_cpu_to_le16( 'R' )
|
||||
};
|
||||
|
||||
static const char mappingdir[] = ".NTFS-3G/";
|
||||
|
||||
@ -146,18 +152,21 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
|
||||
u32 cpuchar;
|
||||
INDEX_ENTRY *entry;
|
||||
FILE_NAME_ATTR *found;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
FILE_NAME_ATTR attr;
|
||||
ntfschar file_name[NTFS_MAX_NAME_LEN + 1];
|
||||
} find;
|
||||
|
||||
mref = ( u64 ) - 1; /* default return (not found) */
|
||||
icx = ntfs_index_ctx_get( dir_ni, NTFS_INDEX_I30, 4 );
|
||||
if (icx) {
|
||||
if ( icx )
|
||||
{
|
||||
if ( uname_len > NTFS_MAX_NAME_LEN )
|
||||
uname_len = NTFS_MAX_NAME_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] );
|
||||
/*
|
||||
* 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 );
|
||||
else
|
||||
entry = icx->entry;
|
||||
if (entry) {
|
||||
if ( entry )
|
||||
{
|
||||
found = &entry->key.file_name;
|
||||
if ( lkup
|
||||
&& 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,
|
||||
vol->upcase, vol->upcase_len ) )
|
||||
lkup = 0;
|
||||
if (!lkup) {
|
||||
if ( !lkup )
|
||||
{
|
||||
/*
|
||||
* name found :
|
||||
* fix original name and return inode
|
||||
@ -228,9 +239,11 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
|
||||
|
||||
target = ( char* )NULL; /* default return */
|
||||
ni = ntfs_inode_open( vol, ( MFT_REF )FILE_root );
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
start = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
len = 0;
|
||||
while ( ( ( start + len ) < count )
|
||||
&& ( 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 );
|
||||
ntfs_inode_close( ni );
|
||||
ni = ( ntfs_inode* )NULL;
|
||||
if (inum != (u64)-1) {
|
||||
if ( inum != ( u64 ) - 1 )
|
||||
{
|
||||
inum = MREF( inum );
|
||||
ni = ntfs_inode_open( vol, inum );
|
||||
start += len;
|
||||
if ( start < count )
|
||||
path[start++] = const_cpu_to_le16( '/' );
|
||||
}
|
||||
} while (ni
|
||||
}
|
||||
while ( ni
|
||||
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
|
||||
&& ( start < count ) );
|
||||
if ( ni
|
||||
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir ) )
|
||||
if (ntfs_ucstombs(path, count, &target, 0) < 0) {
|
||||
if (target) {
|
||||
if ( ntfs_ucstombs( path, count, &target, 0 ) < 0 )
|
||||
{
|
||||
if ( target )
|
||||
{
|
||||
free( target );
|
||||
target = ( char* )NULL;
|
||||
}
|
||||
@ -288,17 +305,22 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
||||
pos = 0;
|
||||
ok = TRUE;
|
||||
curni = ntfs_dir_parent_inode( ni );
|
||||
while (curni && ok && (pos < (count - 1)) && --max) {
|
||||
while ( curni && ok && ( pos < ( count - 1 ) ) && --max )
|
||||
{
|
||||
if ( ( count >= ( pos + 2 ) )
|
||||
&& ( 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( '/' );
|
||||
pos += 2;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( count >= ( pos + 3 ) )
|
||||
&& ( path[pos] == 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( '/' );
|
||||
pos += 3;
|
||||
newni = ntfs_dir_parent_inode( curni );
|
||||
@ -307,7 +329,9 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
||||
curni = newni;
|
||||
if ( !curni )
|
||||
ok = FALSE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
lth = 0;
|
||||
while ( ( ( pos + lth ) < count )
|
||||
&& ( 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 ) )
|
||||
|| ( inum == ( u64 ) - 1 ) )
|
||||
ok = FALSE;
|
||||
else {
|
||||
else
|
||||
{
|
||||
curni = ntfs_inode_open( ni->vol, MREF( inum ) );
|
||||
if ( !curni )
|
||||
ok = FALSE;
|
||||
else {
|
||||
if (ok && ((pos + lth) < count)) {
|
||||
else
|
||||
{
|
||||
if ( ok && ( ( pos + lth ) < count ) )
|
||||
{
|
||||
path[pos + lth] = const_cpu_to_le16( '/' );
|
||||
pos += lth + 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += lth;
|
||||
if ( ( ni->mrec->flags ^ curni->mrec->flags )
|
||||
& 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 ?
|
||||
target = ( char* )NULL;
|
||||
}
|
||||
@ -370,7 +400,8 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
|
||||
ret = -1;
|
||||
drive = ( char* )NULL;
|
||||
sz = ntfs_ucstombs( &letter, 1, &drive, 0 );
|
||||
if (sz > 0) {
|
||||
if ( sz > 0 )
|
||||
{
|
||||
strcpy( defines, mappingdir );
|
||||
if ( ( *drive >= 'a' ) && ( *drive <= 'z' ) )
|
||||
*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 );
|
||||
if ( ni && !ntfs_inode_close( ni ) )
|
||||
ret = 1;
|
||||
else
|
||||
if (errno == ENOENT) {
|
||||
else if ( errno == ENOENT )
|
||||
{
|
||||
ret = 0;
|
||||
/* avoid errno pollution */
|
||||
errno = olderrno;
|
||||
@ -415,8 +446,10 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
|
||||
&& ( size >= sizeof( REPARSE_POINT ) )
|
||||
&& ( ( ( size_t )le16_to_cpu( reparse_attr->reparse_data_length )
|
||||
+ sizeof( REPARSE_POINT ) ) == size );
|
||||
if (ok) {
|
||||
switch (reparse_attr->reparse_tag) {
|
||||
if ( ok )
|
||||
{
|
||||
switch ( reparse_attr->reparse_tag )
|
||||
{
|
||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||
mount_point_data = ( const struct MOUNT_POINT_REPARSE_DATA* )
|
||||
reparse_attr->reparse_data;
|
||||
@ -503,12 +536,15 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
|
||||
if ( ( kind == DIR_JUNCTION )
|
||||
&& ( count >= 7 )
|
||||
&& junction[7]
|
||||
&& !ntfs_drive_letter(vol, junction[4])) {
|
||||
&& !ntfs_drive_letter( vol, junction[4] ) )
|
||||
{
|
||||
target = search_absolute( vol, &junction[7], count - 7, isdir );
|
||||
if (target) {
|
||||
if ( target )
|
||||
{
|
||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||
+ strlen( target ) + 2 );
|
||||
if (fulltarget) {
|
||||
if ( fulltarget )
|
||||
{
|
||||
strcpy( fulltarget, mnt_point );
|
||||
strcat( fulltarget, "/" );
|
||||
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
|
||||
*/
|
||||
if ( ( ( kind == DIR_JUNCTION ) && !fulltarget )
|
||||
|| (kind == VOL_JUNCTION)) {
|
||||
|| ( kind == VOL_JUNCTION ) )
|
||||
{
|
||||
sz = ntfs_ucstombs( &junction[4],
|
||||
( kind == VOL_JUNCTION ? count - 5 : count - 4 ),
|
||||
&target, 0 );
|
||||
if ((sz > 0) && target) {
|
||||
if ( ( sz > 0 ) && target )
|
||||
{
|
||||
/* reverse slashes */
|
||||
for ( q = target; *q; q++ )
|
||||
if ( *q == '\\' )
|
||||
@ -539,7 +577,8 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
|
||||
target[0] += 'A' - 'a';
|
||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||
+ sizeof( mappingdir ) + strlen( target ) + 1 );
|
||||
if (fulltarget) {
|
||||
if ( fulltarget )
|
||||
{
|
||||
strcpy( fulltarget, mnt_point );
|
||||
strcat( fulltarget, "/" );
|
||||
strcat( fulltarget, mappingdir );
|
||||
@ -605,17 +644,20 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
|
||||
&& ( count >= 3 )
|
||||
&& junction[3]
|
||||
&& !ntfs_drive_letter( vol, junction[0] ) )
|
||||
|| (kind == ABS_PATH)) {
|
||||
|| ( kind == ABS_PATH ) )
|
||||
{
|
||||
if ( kind == ABS_PATH )
|
||||
target = search_absolute( vol, &junction[1],
|
||||
count - 1, isdir );
|
||||
else
|
||||
target = search_absolute( vol, &junction[3],
|
||||
count - 3, isdir );
|
||||
if (target) {
|
||||
if ( target )
|
||||
{
|
||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||
+ strlen( target ) + 2 );
|
||||
if (fulltarget) {
|
||||
if ( fulltarget )
|
||||
{
|
||||
strcpy( fulltarget, mnt_point );
|
||||
strcat( fulltarget, "/" );
|
||||
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
|
||||
* define as a symbolic link to the real target
|
||||
*/
|
||||
if ((kind == FULL_PATH) && !fulltarget) {
|
||||
if ( ( kind == FULL_PATH ) && !fulltarget )
|
||||
{
|
||||
sz = ntfs_ucstombs( &junction[0],
|
||||
count, &target, 0 );
|
||||
if ((sz > 0) && target) {
|
||||
if ( ( sz > 0 ) && target )
|
||||
{
|
||||
/* reverse slashes */
|
||||
for ( q = target; *q; q++ )
|
||||
if ( *q == '\\' )
|
||||
@ -643,7 +687,8 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
|
||||
target[0] += 'A' - 'a';
|
||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||
+ sizeof( mappingdir ) + strlen( target ) + 1 );
|
||||
if (fulltarget) {
|
||||
if ( fulltarget )
|
||||
{
|
||||
strcpy( fulltarget, mnt_point );
|
||||
strcat( fulltarget, "/" );
|
||||
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,
|
||||
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
||||
if ( reparse_attr && attr_size
|
||||
&& valid_reparse_data(ni, reparse_attr, attr_size)) {
|
||||
switch (reparse_attr->reparse_tag) {
|
||||
&& valid_reparse_data( ni, reparse_attr, attr_size ) )
|
||||
{
|
||||
switch ( reparse_attr->reparse_tag )
|
||||
{
|
||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||
mount_point_data = ( struct MOUNT_POINT_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,
|
||||
* 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( '?' ) )
|
||||
|| ( *p == const_cpu_to_le16( '\\' ) ) )
|
||||
kind = FULL_TARGET;
|
||||
else
|
||||
kind = ABS_TARGET;
|
||||
} else
|
||||
if (*p == const_cpu_to_le16(':'))
|
||||
}
|
||||
else if ( *p == const_cpu_to_le16( ':' ) )
|
||||
kind = ABS_TARGET;
|
||||
else
|
||||
kind = REL_TARGET;
|
||||
p--;
|
||||
/* reparse data consistency has been checked */
|
||||
switch (kind) {
|
||||
switch ( kind )
|
||||
{
|
||||
case FULL_TARGET :
|
||||
if ( !( symlink_data->flags
|
||||
& const_cpu_to_le32(1))) {
|
||||
& const_cpu_to_le32( 1 ) ) )
|
||||
{
|
||||
target = ntfs_get_fulllink( vol,
|
||||
p, lth / 2,
|
||||
mnt_point, isdir );
|
||||
@ -760,7 +810,8 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
break;
|
||||
case ABS_TARGET :
|
||||
if ( symlink_data->flags
|
||||
& const_cpu_to_le32(1)) {
|
||||
& const_cpu_to_le32( 1 ) )
|
||||
{
|
||||
target = ntfs_get_abslink( vol,
|
||||
p, lth / 2,
|
||||
mnt_point, isdir );
|
||||
@ -770,7 +821,8 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
break;
|
||||
case REL_TARGET :
|
||||
if ( symlink_data->flags
|
||||
& const_cpu_to_le32(1)) {
|
||||
& const_cpu_to_le32( 1 ) )
|
||||
{
|
||||
target = ntfs_get_rellink( ni,
|
||||
p, lth / 2 );
|
||||
if ( target )
|
||||
@ -805,8 +857,10 @@ BOOL ntfs_possible_symlink(ntfs_inode *ni)
|
||||
possible = FALSE;
|
||||
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
||||
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
||||
if (reparse_attr && attr_size) {
|
||||
switch (reparse_attr->reparse_tag) {
|
||||
if ( reparse_attr && attr_size )
|
||||
{
|
||||
switch ( reparse_attr->reparse_tag )
|
||||
{
|
||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||
case IO_REPARSE_TAG_SYMLINK :
|
||||
possible = TRUE;
|
||||
@ -877,10 +931,12 @@ static int remove_reparse_index(ntfs_attr *na, ntfs_index_context *xr,
|
||||
int ret;
|
||||
|
||||
ret = na->data_size;
|
||||
if (ret) {
|
||||
if ( ret )
|
||||
{
|
||||
/* read the existing reparse_tag */
|
||||
size = ntfs_attr_pread( na, 0, 4, preparse_tag );
|
||||
if (size == 4) {
|
||||
if ( size == 4 )
|
||||
{
|
||||
seqn = na->ni->mrec->sequence_number;
|
||||
file_id_cpu = MK_MREF( na->ni->mft_no, le16_to_cpu( seqn ) );
|
||||
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 )
|
||||
&& ntfs_index_rm( xr ) )
|
||||
ret = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -1;
|
||||
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 */
|
||||
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
||||
ni = ( ntfs_inode* )NULL;
|
||||
if (dir_ni) {
|
||||
if ( dir_ni )
|
||||
{
|
||||
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$Reparse" );
|
||||
if ( inum != ( u64 ) - 1 )
|
||||
ni = ntfs_inode_open( vol, inum );
|
||||
ntfs_inode_close( dir_ni );
|
||||
}
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
xr = ntfs_index_ctx_get( ni, reparse_index_name, 2 );
|
||||
if (!xr) {
|
||||
if ( !xr )
|
||||
{
|
||||
ntfs_inode_close( ni );
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
xr = ( ntfs_index_context* )NULL;
|
||||
return ( xr );
|
||||
}
|
||||
@ -959,19 +1021,23 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
||||
|
||||
res = 0;
|
||||
na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
/* remove the existing reparse data */
|
||||
oldsize = remove_reparse_index( na, xr, &reparse_tag );
|
||||
if ( oldsize < 0 )
|
||||
res = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate( na, ( s64 )size );
|
||||
/* overwrite value if any */
|
||||
if (!res && value) {
|
||||
if ( !res && value )
|
||||
{
|
||||
written = ( int )ntfs_attr_pwrite( na,
|
||||
( s64 )0, ( s64 )size, value );
|
||||
if (written != (s64)size) {
|
||||
if ( written != ( s64 )size )
|
||||
{
|
||||
ntfs_log_error( "Failed to update "
|
||||
"reparse data\n" );
|
||||
errno = EIO;
|
||||
@ -981,7 +1047,8 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
||||
if ( !res
|
||||
&& set_reparse_index( ni, xr,
|
||||
( ( const REPARSE_POINT* )value )->reparse_tag )
|
||||
&& (oldsize > 0)) {
|
||||
&& ( oldsize > 0 ) )
|
||||
{
|
||||
/*
|
||||
* If cannot index, try to remove the reparse
|
||||
* 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 );
|
||||
NInoSetDirty( ni );
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = -1;
|
||||
return ( res );
|
||||
}
|
||||
@ -1018,13 +1086,15 @@ int ntfs_delete_reparse_index(ntfs_inode *ni)
|
||||
|
||||
res = 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)
|
||||
* and un-index it
|
||||
*/
|
||||
xr = open_reparse_index( ni->vol );
|
||||
if (xr) {
|
||||
if ( xr )
|
||||
{
|
||||
if ( remove_reparse_index( na, xr, &reparse_tag ) < 0 )
|
||||
res = -1;
|
||||
xrni = xr->ni;
|
||||
@ -1053,12 +1123,16 @@ int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size)
|
||||
s64 attr_size;
|
||||
|
||||
attr_size = 0; /* default to no data and no error */
|
||||
if (ni) {
|
||||
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
|
||||
if ( ni )
|
||||
{
|
||||
if ( ni->flags & FILE_ATTR_REPARSE_POINT )
|
||||
{
|
||||
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
||||
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
||||
if (reparse_attr) {
|
||||
if (attr_size <= (s64)size) {
|
||||
if ( reparse_attr )
|
||||
{
|
||||
if ( attr_size <= ( s64 )size )
|
||||
{
|
||||
if ( value )
|
||||
memcpy( value, reparse_attr,
|
||||
attr_size );
|
||||
@ -1067,7 +1141,8 @@ int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size)
|
||||
}
|
||||
free( reparse_attr );
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
errno = ENODATA;
|
||||
}
|
||||
return ( attr_size ? ( int )attr_size : -errno );
|
||||
@ -1090,43 +1165,57 @@ int ntfs_set_ntfs_reparse_data(ntfs_inode *ni,
|
||||
ntfs_index_context *xr;
|
||||
|
||||
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 );
|
||||
if (xr) {
|
||||
if ( xr )
|
||||
{
|
||||
if ( !ntfs_attr_exist( ni, AT_REPARSE_POINT,
|
||||
AT_UNNAMED,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
AT_UNNAMED, 0 ) )
|
||||
{
|
||||
if ( !( flags & XATTR_REPLACE ) )
|
||||
{
|
||||
/*
|
||||
* no reparse data attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
* Note : NTFS version must be >= 3
|
||||
*/
|
||||
if (ni->vol->major_ver >= 3) {
|
||||
if ( ni->vol->major_ver >= 3 )
|
||||
{
|
||||
res = ntfs_attr_add( ni,
|
||||
AT_REPARSE_POINT,
|
||||
AT_UNNAMED, 0, &dummy,
|
||||
( s64 )0 );
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
ni->flags |=
|
||||
FILE_ATTR_REPARSE_POINT;
|
||||
NInoFileNameSetDirty( ni );
|
||||
}
|
||||
NInoSetDirty( ni );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EOPNOTSUPP;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
if (flags & XATTR_CREATE) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( flags & XATTR_CREATE )
|
||||
{
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
/* update value and index */
|
||||
res = update_reparse_data( ni, xr, value, size );
|
||||
}
|
||||
@ -1135,10 +1224,14 @@ int ntfs_set_ntfs_reparse_data(ntfs_inode *ni,
|
||||
NInoSetDirty( xrni );
|
||||
ntfs_index_ctx_put( xr );
|
||||
ntfs_inode_close( xrni );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
@ -1161,27 +1254,36 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
|
||||
le32 reparse_tag;
|
||||
|
||||
res = 0;
|
||||
if (ni) {
|
||||
if ( ni )
|
||||
{
|
||||
/*
|
||||
* open and delete the reparse data
|
||||
*/
|
||||
na = ntfs_attr_open( ni, AT_REPARSE_POINT,
|
||||
AT_UNNAMED, 0 );
|
||||
if (na) {
|
||||
if ( na )
|
||||
{
|
||||
/* first remove index (reparse data needed) */
|
||||
xr = open_reparse_index( ni->vol );
|
||||
if (xr) {
|
||||
if ( xr )
|
||||
{
|
||||
if ( remove_reparse_index( na, xr,
|
||||
&reparse_tag) < 0) {
|
||||
&reparse_tag ) < 0 )
|
||||
{
|
||||
res = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* now remove attribute */
|
||||
res = ntfs_attr_rm( na );
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
ni->flags &=
|
||||
~FILE_ATTR_REPARSE_POINT;
|
||||
NInoFileNameSetDirty( ni );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If we could not remove the
|
||||
* attribute, try to restore the
|
||||
@ -1207,12 +1309,16 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
|
||||
/* avoid errno pollution */
|
||||
if ( errno == ENOENT )
|
||||
errno = olderrno;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
NInoSetDirty( ni );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
|
@ -127,19 +127,24 @@ runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
|
||||
int last;
|
||||
int irl;
|
||||
|
||||
if (na->rl && rl) {
|
||||
if ( na->rl && rl )
|
||||
{
|
||||
irl = ( int )( rl - na->rl );
|
||||
last = irl;
|
||||
while ( na->rl[last].length )
|
||||
last++;
|
||||
newrl = ntfs_rl_realloc( na->rl, last + 1, last + more_entries + 1 );
|
||||
if (!newrl) {
|
||||
if ( !newrl )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
rl = ( runlist_element* )NULL;
|
||||
} else
|
||||
}
|
||||
else
|
||||
na->rl = newrl;
|
||||
rl = &newrl[irl];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Cannot extend unmapped runlist" );
|
||||
errno = EIO;
|
||||
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 )
|
||||
{
|
||||
if (!dst || !src) {
|
||||
if ( !dst || !src )
|
||||
{
|
||||
ntfs_log_debug( "Eeek. ntfs_rl_are_mergeable() invoked with NULL "
|
||||
"pointer!\n" );
|
||||
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 */
|
||||
int marker; /* End of the inserted runs */
|
||||
|
||||
if (!dst || !src) {
|
||||
if ( !dst || !src )
|
||||
{
|
||||
ntfs_log_debug( "Eeek. ntfs_rl_append() invoked with NULL "
|
||||
"pointer!\n" );
|
||||
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 */
|
||||
int marker; /* End of the inserted runs */
|
||||
|
||||
if (!dst || !src) {
|
||||
if ( !dst || !src )
|
||||
{
|
||||
ntfs_log_debug( "Eeek. ntfs_rl_insert() invoked with NULL "
|
||||
"pointer!\n" );
|
||||
errno = EINVAL;
|
||||
@ -303,7 +311,8 @@ static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize,
|
||||
*/
|
||||
if ( loc == 0 )
|
||||
disc = ( src[0].vcn > 0 );
|
||||
else {
|
||||
else
|
||||
{
|
||||
s64 merged_length;
|
||||
|
||||
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;
|
||||
|
||||
/* Writing beyond the end of the file and there's a discontinuity. */
|
||||
if (disc) {
|
||||
if (loc > 0) {
|
||||
if ( disc )
|
||||
{
|
||||
if ( loc > 0 )
|
||||
{
|
||||
dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length;
|
||||
dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[loc].vcn = 0;
|
||||
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 marker; /* End of the inserted runs */
|
||||
|
||||
if (!dst || !src) {
|
||||
if ( !dst || !src )
|
||||
{
|
||||
ntfs_log_debug( "Eeek. ntfs_rl_replace() invoked with NULL "
|
||||
"pointer!\n" );
|
||||
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.
|
||||
*/
|
||||
delta = ssize - 1 - left - right;
|
||||
if (delta > 0) {
|
||||
if ( delta > 0 )
|
||||
{
|
||||
dst = ntfs_rl_realloc( dst, dsize, dsize + delta );
|
||||
if ( !dst )
|
||||
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,
|
||||
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" );
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
@ -524,10 +540,12 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
||||
return drl;
|
||||
|
||||
/* Check for the case where the first mapping is being done now. */
|
||||
if (!drl) {
|
||||
if ( !drl )
|
||||
{
|
||||
drl = srl;
|
||||
/* Complete the source runlist if necessary. */
|
||||
if (drl[0].vcn) {
|
||||
if ( drl[0].vcn )
|
||||
{
|
||||
/* Scan to the end of the source runlist. */
|
||||
for ( dend = 0; drl[dend].length; dend++ )
|
||||
;
|
||||
@ -551,7 +569,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
||||
si++;
|
||||
|
||||
/* Can't have an entirely unmapped source runlist. */
|
||||
if (!srl[si].length) {
|
||||
if ( !srl[si].length )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: unmapped source runlist", __FUNCTION__ );
|
||||
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
|
||||
* appended to @drl.
|
||||
*/
|
||||
for (; drl[di].length; di++) {
|
||||
for ( ; drl[di].length; di++ )
|
||||
{
|
||||
if ( drl[di].vcn + drl[di].length > srl[sstart].vcn )
|
||||
break;
|
||||
}
|
||||
@ -573,7 +593,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
||||
|
||||
/* Sanity check for illegal overlaps. */
|
||||
if ( ( drl[di].vcn == srl[si].vcn ) && ( drl[di].lcn >= 0 ) &&
|
||||
(srl[si].lcn >= 0)) {
|
||||
( srl[si].lcn >= 0 ) )
|
||||
{
|
||||
errno = ERANGE;
|
||||
ntfs_log_perror( "Run lists overlap. Cannot merge" );
|
||||
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( "ds = %i, ss = %i, dins = %i\n", ds, ss, dins );
|
||||
|
||||
if (start) {
|
||||
if ( start )
|
||||
{
|
||||
if ( finish )
|
||||
drl = ntfs_rl_replace( drl, ds, srl + sstart, ss, dins );
|
||||
else
|
||||
drl = ntfs_rl_insert( drl, ds, srl + sstart, ss, dins );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( finish )
|
||||
drl = ntfs_rl_append( drl, ds, srl + sstart, ss, dins );
|
||||
else
|
||||
drl = ntfs_rl_split( drl, ds, srl + sstart, ss, dins );
|
||||
}
|
||||
if (!drl) {
|
||||
if ( !drl )
|
||||
{
|
||||
ntfs_log_perror( "Merge failed" );
|
||||
return drl;
|
||||
}
|
||||
free( srl );
|
||||
if (marker) {
|
||||
if ( marker )
|
||||
{
|
||||
ntfs_log_debug( "Triggering marker code.\n" );
|
||||
for ( ds = dend; drl[ds].length; ds++ )
|
||||
;
|
||||
/* 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;
|
||||
|
||||
if (drl[ds].vcn == marker_vcn) {
|
||||
if ( drl[ds].vcn == marker_vcn )
|
||||
{
|
||||
ntfs_log_debug( "Old marker = %lli, replacing with "
|
||||
"LCN_ENOENT.\n",
|
||||
( 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
|
||||
* ENOENT terminator.
|
||||
*/
|
||||
if (drl[ds].lcn == (LCN)LCN_ENOENT) {
|
||||
if ( drl[ds].lcn == ( LCN )LCN_ENOENT )
|
||||
{
|
||||
ds--;
|
||||
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. */
|
||||
if (!slots) {
|
||||
if ( !slots )
|
||||
{
|
||||
/* FIXME/TODO: We need to have the
|
||||
* 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;
|
||||
/* Finally add the ENOENT terminator. */
|
||||
ds++;
|
||||
if (!slots) {
|
||||
if ( !slots )
|
||||
{
|
||||
/* FIXME/TODO: We need to have the extra
|
||||
* 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 ) );
|
||||
/* Make sure attr exists and is 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;
|
||||
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. */
|
||||
buf = ( const u8* )attr + le16_to_cpu( attr->mapping_pairs_offset );
|
||||
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" );
|
||||
errno = EIO;
|
||||
return NULL;
|
||||
@ -820,23 +854,27 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
||||
if ( !rl )
|
||||
return NULL;
|
||||
/* Insert unmapped starting element if necessary. */
|
||||
if (vcn) {
|
||||
if ( vcn )
|
||||
{
|
||||
rl->vcn = ( VCN )0;
|
||||
rl->lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
||||
rl->length = vcn;
|
||||
rlpos++;
|
||||
}
|
||||
while (buf < attr_end && *buf) {
|
||||
while ( buf < attr_end && *buf )
|
||||
{
|
||||
/*
|
||||
* Allocate more memory if needed, including space for the
|
||||
* not-mapped and terminator elements.
|
||||
*/
|
||||
if ((int)((rlpos + 3) * sizeof(*old_rl)) > rlsize) {
|
||||
if ( ( int )( ( rlpos + 3 ) * sizeof( *old_rl ) ) > rlsize )
|
||||
{
|
||||
runlist_element *rl2;
|
||||
|
||||
rlsize += 0x1000;
|
||||
rl2 = realloc( rl, rlsize );
|
||||
if (!rl2) {
|
||||
if ( !rl2 )
|
||||
{
|
||||
int eo = errno;
|
||||
free( rl );
|
||||
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...
|
||||
*/
|
||||
b = *buf & 0xf;
|
||||
if (b) {
|
||||
if ( b )
|
||||
{
|
||||
if ( buf + b > attr_end )
|
||||
goto io_error;
|
||||
for ( deltaxcn = ( s8 )buf[b--]; b; 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 "
|
||||
"array.\n" );
|
||||
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
|
||||
* hence clean-up and return NULL.
|
||||
*/
|
||||
if (deltaxcn < 0) {
|
||||
if ( deltaxcn < 0 )
|
||||
{
|
||||
ntfs_log_debug( "Invalid length in mapping pairs array.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
@ -886,7 +928,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
||||
*/
|
||||
if ( !( *buf & 0xf0 ) )
|
||||
rl[rlpos].lcn = ( LCN )LCN_HOLE;
|
||||
else {
|
||||
else
|
||||
{
|
||||
/* Get the lcn change which really can be negative. */
|
||||
u8 b2 = *buf & 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
|
||||
* can investigate it further!
|
||||
*/
|
||||
if (vol->major_ver < 3) {
|
||||
if ( vol->major_ver < 3 )
|
||||
{
|
||||
if ( deltaxcn == ( LCN ) - 1 )
|
||||
ntfs_log_debug( "lcn delta == -1\n" );
|
||||
if ( lcn == ( LCN ) - 1 )
|
||||
@ -912,7 +956,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
||||
}
|
||||
#endif
|
||||
/* Check lcn is not below -1. */
|
||||
if (lcn < (LCN)-1) {
|
||||
if ( lcn < ( LCN ) - 1 )
|
||||
{
|
||||
ntfs_log_debug( "Invalid LCN < -1 in mapping pairs "
|
||||
"array.\n" );
|
||||
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.
|
||||
*/
|
||||
deltaxcn = sle64_to_cpu( attr->highest_vcn );
|
||||
if (deltaxcn && vcn - 1 != deltaxcn) {
|
||||
if ( deltaxcn && vcn - 1 != deltaxcn )
|
||||
{
|
||||
mpa_err:
|
||||
ntfs_log_debug( "Corrupt mapping pairs array in non-resident "
|
||||
"attribute.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
/* Setup not mapped runlist element if this is the base extent. */
|
||||
if (!attr->lowest_vcn) {
|
||||
if ( !attr->lowest_vcn )
|
||||
{
|
||||
VCN max_cluster;
|
||||
|
||||
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
|
||||
* attribute so simply terminate the runlist with LCN_ENOENT).
|
||||
*/
|
||||
if (deltaxcn) {
|
||||
if ( deltaxcn )
|
||||
{
|
||||
/*
|
||||
* If there is a difference between the highest_vcn and
|
||||
* the highest cluster, the runlist is either corrupt
|
||||
* or, more likely, there are more extents following
|
||||
* this one.
|
||||
*/
|
||||
if (deltaxcn < max_cluster) {
|
||||
if ( deltaxcn < max_cluster )
|
||||
{
|
||||
ntfs_log_debug( "More extents to follow; deltaxcn = "
|
||||
"0x%llx, max_cluster = 0x%llx\n",
|
||||
( long long )deltaxcn,
|
||||
@ -965,7 +1014,9 @@ mpa_err:
|
||||
vcn += rl[rlpos].length = max_cluster - deltaxcn;
|
||||
rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
||||
rlpos++;
|
||||
} else if (deltaxcn > max_cluster) {
|
||||
}
|
||||
else if ( deltaxcn > max_cluster )
|
||||
{
|
||||
ntfs_log_debug( "Corrupt attribute. deltaxcn = "
|
||||
"0x%llx, max_cluster = 0x%llx\n",
|
||||
( long long )deltaxcn,
|
||||
@ -974,14 +1025,16 @@ mpa_err:
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
/* Setup terminating runlist element. */
|
||||
rl[rlpos].vcn = vcn;
|
||||
rl[rlpos].length = ( s64 )0;
|
||||
/* 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_debug_runlist_dump( 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 )
|
||||
return ( LCN )LCN_ENOENT;
|
||||
|
||||
for (i = 0; rl[i].length; i++) {
|
||||
if (vcn < rl[i+1].vcn) {
|
||||
for ( i = 0; rl[i].length; i++ )
|
||||
{
|
||||
if ( vcn < rl[i+1].vcn )
|
||||
{
|
||||
if ( rl[i].lcn >= ( LCN )0 )
|
||||
return rl[i].lcn + ( vcn - rl[i].vcn );
|
||||
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;
|
||||
int err = EIO;
|
||||
|
||||
if (!vol || !rl || pos < 0 || count < 0) {
|
||||
if ( !vol || !rl || pos < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "Failed to read runlist [vol: %p rl: %p "
|
||||
"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 );
|
||||
/* Offset in the run at which to begin reading. */
|
||||
ofs = pos - ofs;
|
||||
for (total = 0LL; count; rl++, ofs = 0) {
|
||||
for ( total = 0LL; count; rl++, ofs = 0 )
|
||||
{
|
||||
if ( !rl->length )
|
||||
goto rl_err_out;
|
||||
if (rl->lcn < (LCN)0) {
|
||||
if ( rl->lcn < ( LCN )0 )
|
||||
{
|
||||
if ( rl->lcn != ( LCN )LCN_HOLE )
|
||||
goto rl_err_out;
|
||||
/* It is a hole. Just fill buffer @b with zeroes. */
|
||||
@ -1136,7 +1194,8 @@ retry:
|
||||
bytes_read = ntfs_pread( vol->dev, ( rl->lcn <<
|
||||
vol->cluster_size_bits ) + ofs, to_read, b );
|
||||
/* If everything ok, update progress counters and continue. */
|
||||
if (bytes_read > 0) {
|
||||
if ( bytes_read > 0 )
|
||||
{
|
||||
total += bytes_read;
|
||||
count -= 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;
|
||||
int err = EIO;
|
||||
|
||||
if (!vol || !rl || pos < 0 || count < 0) {
|
||||
if ( !vol || !rl || pos < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "Failed to write runlist [vol: %p rl: %p "
|
||||
"pos: %lld count: %lld]", vol, rl,
|
||||
@ -1198,16 +1258,19 @@ s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
|
||||
goto out;
|
||||
/* Seek in @rl to the run containing @pos. */
|
||||
while ( rl->length && ( ofs + ( rl->length <<
|
||||
vol->cluster_size_bits) <= pos)) {
|
||||
vol->cluster_size_bits ) <= pos ) )
|
||||
{
|
||||
ofs += ( rl->length << vol->cluster_size_bits );
|
||||
rl++;
|
||||
}
|
||||
/* Offset in the run at which to begin writing. */
|
||||
ofs = pos - ofs;
|
||||
for (total = 0LL; count; rl++, ofs = 0) {
|
||||
for ( total = 0LL; count; rl++, ofs = 0 )
|
||||
{
|
||||
if ( !rl->length )
|
||||
goto rl_err_out;
|
||||
if (rl->lcn < (LCN)0) {
|
||||
if ( rl->lcn < ( LCN )0 )
|
||||
{
|
||||
|
||||
if ( rl->lcn != ( LCN )LCN_HOLE )
|
||||
goto rl_err_out;
|
||||
@ -1231,7 +1294,8 @@ retry:
|
||||
else
|
||||
written = to_write;
|
||||
/* If everything ok, update progress counters and continue. */
|
||||
if (written > 0) {
|
||||
if ( written > 0 )
|
||||
{
|
||||
total += written;
|
||||
count -= written;
|
||||
b = ( u8* )b + written;
|
||||
@ -1275,12 +1339,15 @@ int ntfs_get_nr_significant_bytes(const s64 n)
|
||||
|
||||
l = ( n < 0 ? ~n : n );
|
||||
i = 1;
|
||||
if (l >= 128) {
|
||||
if ( l >= 128 )
|
||||
{
|
||||
l >>= 7;
|
||||
do {
|
||||
do
|
||||
{
|
||||
i++;
|
||||
l >>= 8;
|
||||
} while (l);
|
||||
}
|
||||
while ( l );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@ -1311,14 +1378,17 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||
LCN prev_lcn;
|
||||
int rls;
|
||||
|
||||
if (start_vcn < 0) {
|
||||
if ( start_vcn < 0 )
|
||||
{
|
||||
ntfs_log_trace( "start_vcn %lld (should be >= 0)\n",
|
||||
( long long ) start_vcn );
|
||||
errno = EINVAL;
|
||||
goto errno_set;
|
||||
}
|
||||
if (!rl) {
|
||||
if (start_vcn) {
|
||||
if ( !rl )
|
||||
{
|
||||
if ( start_vcn )
|
||||
{
|
||||
ntfs_log_trace( "rl NULL, start_vcn %lld (should be > 0)\n",
|
||||
( long long ) start_vcn );
|
||||
errno = EINVAL;
|
||||
@ -1330,7 +1400,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||
/* Skip to runlist element containing @start_vcn. */
|
||||
while ( rl->length && start_vcn >= rl[1].vcn )
|
||||
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;
|
||||
goto errno_set;
|
||||
}
|
||||
@ -1338,7 +1409,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||
/* Always need the terminating zero byte. */
|
||||
rls = 1;
|
||||
/* Do the first partial run if present. */
|
||||
if (start_vcn > rl->vcn) {
|
||||
if ( start_vcn > rl->vcn )
|
||||
{
|
||||
s64 delta;
|
||||
|
||||
/* 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
|
||||
* 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;
|
||||
if ( rl->lcn >= 0 )
|
||||
prev_lcn += delta;
|
||||
@ -1365,7 +1438,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||
rl++;
|
||||
}
|
||||
/* 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 )
|
||||
goto err_out;
|
||||
/* 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
|
||||
* 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. */
|
||||
rls += ntfs_get_nr_significant_bytes( rl->lcn -
|
||||
prev_lcn );
|
||||
@ -1421,21 +1496,26 @@ int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n)
|
||||
s8 j;
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
if ( dst > dst_max )
|
||||
goto err_out;
|
||||
*dst++ = l & 0xffLL;
|
||||
l >>= 8;
|
||||
i++;
|
||||
} while (l != 0LL && l != -1LL);
|
||||
}
|
||||
while ( l != 0LL && l != -1LL );
|
||||
j = ( n >> 8 * ( i - 1 ) ) & 0xff;
|
||||
/* 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 )
|
||||
goto err_out;
|
||||
i++;
|
||||
*dst = ( u8 ) - 1;
|
||||
} else if (n > 0LL && j < 0) {
|
||||
}
|
||||
else if ( n > 0LL && j < 0 )
|
||||
{
|
||||
if ( dst > dst_max )
|
||||
goto err_out;
|
||||
i++;
|
||||
@ -1489,7 +1569,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
||||
|
||||
if ( start_vcn < 0 )
|
||||
goto val_err;
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
if ( start_vcn )
|
||||
goto val_err;
|
||||
if ( stop_rl )
|
||||
@ -1510,7 +1591,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
||||
dst_max = dst + dst_len - 1;
|
||||
prev_lcn = 0;
|
||||
/* Do the first partial run if present. */
|
||||
if (start_vcn > rl->vcn) {
|
||||
if ( start_vcn > rl->vcn )
|
||||
{
|
||||
s64 delta;
|
||||
|
||||
/* 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
|
||||
* 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;
|
||||
if ( rl->lcn >= 0 )
|
||||
prev_lcn += delta;
|
||||
@ -1540,7 +1623,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
||||
len_len, dst_max, prev_lcn );
|
||||
if ( lcn_len < 0 )
|
||||
goto size_err;
|
||||
} else
|
||||
}
|
||||
else
|
||||
lcn_len = 0;
|
||||
dst_next = dst + len_len + lcn_len + 1;
|
||||
if ( dst_next > dst_max )
|
||||
@ -1553,7 +1637,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
||||
rl++;
|
||||
}
|
||||
/* Do the full runs. */
|
||||
for (; rl->length; rl++) {
|
||||
for ( ; rl->length; rl++ )
|
||||
{
|
||||
if ( rl->length < 0 || rl->lcn < LCN_HOLE )
|
||||
goto err_out;
|
||||
/* 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
|
||||
* 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. */
|
||||
lcn_len = ntfs_write_significant_bytes( dst + 1 +
|
||||
len_len, dst_max, rl->lcn - prev_lcn );
|
||||
if ( lcn_len < 0 )
|
||||
goto size_err;
|
||||
prev_lcn = rl->lcn;
|
||||
} else
|
||||
}
|
||||
else
|
||||
lcn_len = 0;
|
||||
dst_next = dst + len_len + lcn_len + 1;
|
||||
if ( dst_next > dst_max )
|
||||
@ -1635,7 +1722,8 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
|
||||
runlist *rl;
|
||||
BOOL is_end = FALSE;
|
||||
|
||||
if (!arl || !*arl) {
|
||||
if ( !arl || !*arl )
|
||||
{
|
||||
errno = EINVAL;
|
||||
if ( !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;
|
||||
|
||||
if (start_vcn < rl->vcn) {
|
||||
if ( start_vcn < rl->vcn )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "Start_vcn lies outside front of runlist" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find the starting vcn in the run list. */
|
||||
while (rl->length) {
|
||||
while ( rl->length )
|
||||
{
|
||||
if ( start_vcn < rl[1].vcn )
|
||||
break;
|
||||
rl++;
|
||||
}
|
||||
|
||||
if (!rl->length) {
|
||||
if ( !rl->length )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_trace( "Truncating already truncated runlist?\n" );
|
||||
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 itself.
|
||||
*/
|
||||
if (rl->length) {
|
||||
if ( rl->length )
|
||||
{
|
||||
++rl;
|
||||
if ( !rl->length )
|
||||
is_end = TRUE;
|
||||
@ -1708,15 +1800,18 @@ int ntfs_rl_sparse(runlist *rl)
|
||||
{
|
||||
runlist *rlc;
|
||||
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: ", __FUNCTION__ );
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
|
||||
return -1;
|
||||
@ -1738,20 +1833,25 @@ s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl)
|
||||
runlist *rlc;
|
||||
s64 ret = 0;
|
||||
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: ", __FUNCTION__ );
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rlc = rl; rlc->length; rlc++) {
|
||||
if (rlc->lcn < 0) {
|
||||
if (rlc->lcn != LCN_HOLE) {
|
||||
for ( rlc = rl; rlc->length; rlc++ )
|
||||
{
|
||||
if ( rlc->lcn < 0 )
|
||||
{
|
||||
if ( rlc->lcn != LCN_HOLE )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
ret += rlc->length;
|
||||
}
|
||||
return ret << vol->cluster_size_bits;
|
||||
@ -1784,7 +1884,8 @@ static void test_rl_dump_runlist(const runlist_element *rl)
|
||||
int i;
|
||||
const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "XXXX" };
|
||||
|
||||
if (!rl) {
|
||||
if ( !rl )
|
||||
{
|
||||
printf( " Run list not present.\n" );
|
||||
return;
|
||||
}
|
||||
@ -1793,24 +1894,28 @@ static void test_rl_dump_runlist(const runlist_element *rl)
|
||||
for ( len = 0; rl[len].length; len++ ) ;
|
||||
|
||||
printf( " VCN LCN len\n" );
|
||||
for (i = 0; ; i++, rl++) {
|
||||
for ( i = 0; ; i++, rl++ )
|
||||
{
|
||||
LCN lcn = rl->lcn;
|
||||
|
||||
if ((abbr) && (len > 20)) {
|
||||
if ( ( abbr ) && ( len > 20 ) )
|
||||
{
|
||||
if ( i == 4 )
|
||||
printf( " ...\n" );
|
||||
if ( ( i > 3 ) && ( i < ( len - 3 ) ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lcn < (LCN)0) {
|
||||
if ( lcn < ( LCN )0 )
|
||||
{
|
||||
int ind = -lcn - 1;
|
||||
|
||||
if ( ind > -LCN_ENOENT - 1 )
|
||||
ind = 3;
|
||||
printf( "%8lld %8s %8lld\n",
|
||||
rl->vcn, lcn_str[ind], rl->length );
|
||||
} else
|
||||
}
|
||||
else
|
||||
printf( "%8lld %8lld %8lld\n",
|
||||
rl->vcn, rl->lcn, rl->length );
|
||||
if ( !rl->length )
|
||||
@ -1862,12 +1967,14 @@ static int test_rl_read_buffer(const char *file, u8 *buf, int bufsize)
|
||||
FILE *fptr;
|
||||
|
||||
fptr = fopen( file, "r" );
|
||||
if (!fptr) {
|
||||
if ( !fptr )
|
||||
{
|
||||
printf( "open %s\n", file );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fread(buf, bufsize, 1, fptr) == 99) {
|
||||
if ( fread( buf, bufsize, 1, fptr ) == 99 )
|
||||
{
|
||||
printf( "read %s\n", file );
|
||||
return 0;
|
||||
}
|
||||
@ -1901,13 +2008,16 @@ static runlist_element * test_rl_pure_src(BOOL contig, BOOL multi, int vcn, int
|
||||
if ( !result )
|
||||
return NULL;
|
||||
|
||||
if (multi) {
|
||||
if ( multi )
|
||||
{
|
||||
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 + 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 + 4, vcn + ( 4*len / 4 ), LCN_RL_NOT_MAPPED, 0 )
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
MKRL( result + 0, vcn, fudge + vcn + 1000, len )
|
||||
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 );
|
||||
dst = ntfs_malloc( 4096 );
|
||||
if (!src || !dst) {
|
||||
if ( !src || !dst )
|
||||
{
|
||||
printf( "Test %2d ---------- FAILED! (no free memory?)\n", test );
|
||||
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 )
|
||||
{
|
||||
/* VCN, LCN, len */
|
||||
static runlist_element file1[] = {
|
||||
static runlist_element file1[] =
|
||||
{
|
||||
{ 0, -1, 100 }, /* HOLE */
|
||||
{ 100, 1100, 100 }, /* DATA */
|
||||
{ 200, -1, 100 }, /* HOLE */
|
||||
@ -1969,19 +2081,23 @@ static void test_rl_pure(char *contig, char *multi)
|
||||
{ 400, -1, 100 }, /* HOLE */
|
||||
{ 500, -3, 0 } /* NOENT */
|
||||
};
|
||||
static runlist_element file2[] = {
|
||||
static runlist_element file2[] =
|
||||
{
|
||||
{ 0, 1000, 100 }, /* DATA */
|
||||
{ 100, -1, 100 }, /* HOLE */
|
||||
{ 200, -3, 0 } /* NOENT */
|
||||
};
|
||||
static runlist_element file3[] = {
|
||||
static runlist_element file3[] =
|
||||
{
|
||||
{ 0, 1000, 100 }, /* DATA */
|
||||
{ 100, -3, 0 } /* NOENT */
|
||||
};
|
||||
static runlist_element file4[] = {
|
||||
static runlist_element file4[] =
|
||||
{
|
||||
{ 0, -3, 0 } /* NOENT */
|
||||
};
|
||||
static runlist_element file5[] = {
|
||||
static runlist_element file5[] =
|
||||
{
|
||||
{ 0, -2, 100 }, /* NOTMAP */
|
||||
{ 100, 1100, 100 }, /* DATA */
|
||||
{ 200, -2, 100 }, /* NOTMAP */
|
||||
@ -1989,7 +2105,8 @@ static void test_rl_pure(char *contig, char *multi)
|
||||
{ 400, -2, 100 }, /* NOTMAP */
|
||||
{ 500, -3, 0 } /* NOENT */
|
||||
};
|
||||
static runlist_element file6[] = {
|
||||
static runlist_element file6[] =
|
||||
{
|
||||
{ 0, 1000, 100 }, /* DATA */
|
||||
{ 100, -2, 100 }, /* NOTMAP */
|
||||
{ 200, -3, 0 } /* NOENT */
|
||||
@ -2000,7 +2117,8 @@ static void test_rl_pure(char *contig, char *multi)
|
||||
c = TRUE;
|
||||
else if ( strcmp( contig, "noncontig" ) == 0 )
|
||||
c = FALSE;
|
||||
else {
|
||||
else
|
||||
{
|
||||
printf( "rl pure [contig|noncontig] [single|multi]\n" );
|
||||
return;
|
||||
}
|
||||
@ -2008,7 +2126,8 @@ static void test_rl_pure(char *contig, char *multi)
|
||||
m = TRUE;
|
||||
else if ( strcmp( multi, "single" ) == 0 )
|
||||
m = FALSE;
|
||||
else {
|
||||
else
|
||||
{
|
||||
printf( "rl pure [contig|noncontig] [single|multi]\n" );
|
||||
return;
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ typedef runlist_element runlist;
|
||||
* 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).
|
||||
*/
|
||||
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. */
|
||||
LCN lcn; /* lcn = Starting logical cluster number. */
|
||||
s64 length; /* Run length in clusters. */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,7 +50,8 @@ typedef u32 be32;
|
||||
* item in the mapping list
|
||||
*/
|
||||
|
||||
struct MAPPING {
|
||||
struct MAPPING
|
||||
{
|
||||
struct MAPPING *next;
|
||||
int xid; /* linux id : uid or gid */
|
||||
SID *sid; /* Windows id : usid or gsid */
|
||||
@ -63,7 +64,8 @@ struct MAPPING {
|
||||
* Note : this cache is not organized as a generic cache
|
||||
*/
|
||||
|
||||
struct CACHED_PERMISSIONS {
|
||||
struct CACHED_PERMISSIONS
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
le32 inh_fileid;
|
||||
@ -80,7 +82,8 @@ struct CACHED_PERMISSIONS {
|
||||
* 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 *previous;
|
||||
void *variable;
|
||||
@ -94,7 +97,8 @@ struct CACHED_PERMISSIONS_LEGACY {
|
||||
* Entry in the securid cache
|
||||
*/
|
||||
|
||||
struct CACHED_SECURID {
|
||||
struct CACHED_SECURID
|
||||
{
|
||||
struct CACHED_SECURID *next;
|
||||
struct CACHED_SECURID *previous;
|
||||
void *variable;
|
||||
@ -111,7 +115,8 @@ struct CACHED_SECURID {
|
||||
* (has no cache structure by itself)
|
||||
*/
|
||||
|
||||
struct CACHED_PERMISSIONS_HEADER {
|
||||
struct CACHED_PERMISSIONS_HEADER
|
||||
{
|
||||
unsigned int last;
|
||||
/* statistics for permissions */
|
||||
unsigned long p_writes;
|
||||
@ -123,7 +128,8 @@ struct CACHED_PERMISSIONS_HEADER {
|
||||
* The whole permissions cache
|
||||
*/
|
||||
|
||||
struct PERMISSIONS_CACHE {
|
||||
struct PERMISSIONS_CACHE
|
||||
{
|
||||
struct CACHED_PERMISSIONS_HEADER head;
|
||||
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
|
||||
} ;
|
||||
@ -132,7 +138,8 @@ struct PERMISSIONS_CACHE {
|
||||
* Security flags values
|
||||
*/
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
||||
SECURITY_RAW, /* force same ownership/permissions on files */
|
||||
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
||||
@ -146,7 +153,8 @@ enum {
|
||||
|
||||
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
|
||||
|
||||
struct SECURITY_CONTEXT {
|
||||
struct SECURITY_CONTEXT
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
struct MAPPING *mapping[MAPCOUNT];
|
||||
struct PERMISSIONS_CACHE **pseccache;
|
||||
@ -162,20 +170,23 @@ struct SECURITY_CONTEXT {
|
||||
* Posix ACL structures
|
||||
*/
|
||||
|
||||
struct POSIX_ACE {
|
||||
struct POSIX_ACE
|
||||
{
|
||||
u16 tag;
|
||||
u16 perms;
|
||||
s32 id;
|
||||
} ;
|
||||
|
||||
struct POSIX_ACL {
|
||||
struct POSIX_ACL
|
||||
{
|
||||
u8 version;
|
||||
u8 flags;
|
||||
u16 filler;
|
||||
struct POSIX_ACE ace[0];
|
||||
} ;
|
||||
|
||||
struct POSIX_SECURITY {
|
||||
struct POSIX_SECURITY
|
||||
{
|
||||
mode_t mode;
|
||||
int acccnt;
|
||||
int defcnt;
|
||||
@ -188,7 +199,8 @@ struct POSIX_SECURITY {
|
||||
* Posix tags, cpu-endian 16 bits
|
||||
*/
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
POSIX_ACL_USER_OBJ = 1,
|
||||
POSIX_ACL_USER = 2,
|
||||
POSIX_ACL_GROUP_OBJ = 4,
|
||||
@ -204,7 +216,8 @@ enum {
|
||||
* Posix permissions, cpu-endian 16 bits
|
||||
*/
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
POSIX_PERM_X = 1,
|
||||
POSIX_PERM_W = 2,
|
||||
POSIX_PERM_R = 4,
|
||||
@ -310,7 +323,8 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni,
|
||||
|
||||
#define MAGIC_API 0x09042009
|
||||
|
||||
struct SECURITY_API {
|
||||
struct SECURITY_API
|
||||
{
|
||||
u32 magic;
|
||||
struct SECURITY_CONTEXT security;
|
||||
struct PERMISSIONS_CACHE *seccache;
|
||||
|
@ -92,7 +92,8 @@ typedef sle64 leLSN;
|
||||
/**
|
||||
* enum BOOL - These are just to make the code more readable...
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
#ifndef FALSE
|
||||
FALSE = 0,
|
||||
#endif
|
||||
@ -118,7 +119,8 @@ typedef enum {
|
||||
/**
|
||||
* enum IGNORE_CASE_BOOL -
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
} IGNORE_CASE_BOOL;
|
||||
|
@ -88,7 +88,8 @@ static int nfconvert_utf8 = 1;
|
||||
* characters are (in)valid.
|
||||
*/
|
||||
#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,
|
||||
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;
|
||||
|
||||
#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" );
|
||||
exit( 1 );
|
||||
}
|
||||
#endif
|
||||
cnt = min( name1_len, name2_len );
|
||||
if (cnt > 0) {
|
||||
if (ic == CASE_SENSITIVE) {
|
||||
do {
|
||||
if ( cnt > 0 )
|
||||
{
|
||||
if ( ic == CASE_SENSITIVE )
|
||||
{
|
||||
do
|
||||
{
|
||||
c1 = le16_to_cpu( *name1 );
|
||||
name1++;
|
||||
c2 = le16_to_cpu( *name2 );
|
||||
name2++;
|
||||
} while (--cnt && (c1 == c2));
|
||||
}
|
||||
while ( --cnt && ( c1 == c2 ) );
|
||||
u1 = c1;
|
||||
u2 = c2;
|
||||
if ( u1 < upcase_len )
|
||||
@ -179,7 +185,8 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
if ( u2 < upcase_len )
|
||||
u2 = le16_to_cpu( upcase[u2] );
|
||||
if ( ( u1 == u2 ) && cnt )
|
||||
do {
|
||||
do
|
||||
{
|
||||
u1 = le16_to_cpu( *name1 );
|
||||
name1++;
|
||||
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] );
|
||||
if ( u2 < upcase_len )
|
||||
u2 = le16_to_cpu( upcase[u2] );
|
||||
} while ((u1 == u2) && --cnt);
|
||||
}
|
||||
while ( ( u1 == u2 ) && --cnt );
|
||||
if ( u1 < u2 )
|
||||
return -1;
|
||||
if ( u1 > u2 )
|
||||
@ -201,8 +209,11 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
return -1;
|
||||
if ( c1 > c2 )
|
||||
return 1;
|
||||
} else {
|
||||
do {
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
u1 = c1 = le16_to_cpu( *name1 );
|
||||
name1++;
|
||||
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] );
|
||||
if ( u2 < upcase_len )
|
||||
u2 = le16_to_cpu( upcase[u2] );
|
||||
} while ((u1 == u2) && --cnt);
|
||||
}
|
||||
while ( ( u1 == u2 ) && --cnt );
|
||||
if ( u1 < u2 )
|
||||
return -1;
|
||||
if ( u1 > u2 )
|
||||
@ -221,7 +233,9 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
if ( name1_len > name2_len )
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( name1_len < name2_len )
|
||||
return -1;
|
||||
if ( name1_len > name2_len )
|
||||
@ -250,12 +264,14 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
|
||||
size_t i;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!s1 || !s2) {
|
||||
if ( !s1 || !s2 )
|
||||
{
|
||||
ntfs_log_debug( "ntfs_wcsncmp() received NULL pointer!\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < n; ++i) {
|
||||
for ( i = 0; i < n; ++i )
|
||||
{
|
||||
c1 = le16_to_cpu( s1[i] );
|
||||
c2 = le16_to_cpu( s2[i] );
|
||||
if ( c1 < c2 )
|
||||
@ -293,12 +309,14 @@ int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
|
||||
size_t i;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!s1 || !s2 || !upcase) {
|
||||
if ( !s1 || !s2 || !upcase )
|
||||
{
|
||||
ntfs_log_debug( "ntfs_wcsncasecmp() received NULL pointer!\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < n; ++i) {
|
||||
for ( i = 0; i < n; ++i )
|
||||
{
|
||||
if ( ( c1 = le16_to_cpu( s1[i] ) ) < upcase_size )
|
||||
c1 = le16_to_cpu( upcase[c1] );
|
||||
if ( ( c2 = le16_to_cpu( s2[i] ) ) < upcase_size )
|
||||
@ -329,7 +347,8 @@ u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
for ( i = 0; i < maxlen; i++ )
|
||||
{
|
||||
if ( !le16_to_cpu( s[i] ) )
|
||||
break;
|
||||
}
|
||||
@ -360,7 +379,8 @@ ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
|
||||
|
||||
len = ntfs_ucsnlen( s, maxlen );
|
||||
dst = ntfs_malloc( ( len + 1 ) * sizeof( ntfschar ) );
|
||||
if (dst) {
|
||||
if ( dst )
|
||||
{
|
||||
memcpy( dst, s, len * sizeof( ntfschar ) );
|
||||
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;
|
||||
|
||||
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] );
|
||||
if (surrog) {
|
||||
if ((c >= 0xdc00) && (c < 0xe000)) {
|
||||
if ( surrog )
|
||||
{
|
||||
if ( ( c >= 0xdc00 ) && ( c < 0xe000 ) )
|
||||
{
|
||||
surrog = FALSE;
|
||||
count += 4;
|
||||
} else
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
} else
|
||||
if (c < 0x80)
|
||||
}
|
||||
else if ( c < 0x80 )
|
||||
count++;
|
||||
else if ( c < 0x800 )
|
||||
count += 2;
|
||||
@ -483,7 +507,8 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
|
||||
count += 3;
|
||||
else
|
||||
goto fail;
|
||||
if (count > outs_len) {
|
||||
if ( count > outs_len )
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
@ -531,7 +556,8 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
||||
if ( size < 0 )
|
||||
goto out;
|
||||
|
||||
if (!*outs) {
|
||||
if ( !*outs )
|
||||
{
|
||||
outs_len = size + 1;
|
||||
*outs = ntfs_malloc( outs_len );
|
||||
if ( !*outs )
|
||||
@ -540,35 +566,49 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
||||
|
||||
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] );
|
||||
/* size not double-checked */
|
||||
if (halfpair) {
|
||||
if ((c >= 0xdc00) && (c < 0xe000)) {
|
||||
if ( halfpair )
|
||||
{
|
||||
if ( ( c >= 0xdc00 ) && ( c < 0xe000 ) )
|
||||
{
|
||||
*t++ = 0xf0 + ( ( ( halfpair + 64 ) >> 8 ) & 7 );
|
||||
*t++ = 0x80 + ( ( ( halfpair + 64 ) >> 2 ) & 63 );
|
||||
*t++ = 0x80 + ( ( c >> 6 ) & 15 ) + ( ( halfpair & 3 ) << 4 );
|
||||
*t++ = 0x80 + ( c & 63 );
|
||||
halfpair = 0;
|
||||
} else
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
} else if (c < 0x80) {
|
||||
}
|
||||
else if ( c < 0x80 )
|
||||
{
|
||||
*t++ = c;
|
||||
} else {
|
||||
if (c < 0x800) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( c < 0x800 )
|
||||
{
|
||||
*t++ = ( 0xc0 | ( ( c >> 6 ) & 0x3f ) );
|
||||
*t++ = 0x80 | ( c & 0x3f );
|
||||
} else if (c < 0xd800) {
|
||||
}
|
||||
else if ( c < 0xd800 )
|
||||
{
|
||||
*t++ = 0xe0 | ( c >> 12 );
|
||||
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
|
||||
*t++ = 0x80 | ( c & 0x3f );
|
||||
} else if (c < 0xdc00)
|
||||
}
|
||||
else if ( c < 0xdc00 )
|
||||
halfpair = c;
|
||||
else if (c >= 0xe000) {
|
||||
else if ( c >= 0xe000 )
|
||||
{
|
||||
*t++ = 0xe0 | ( c >> 12 );
|
||||
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
|
||||
*t++ = 0x80 | ( c & 0x3f );
|
||||
} else
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@ -576,17 +616,21 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
||||
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#ifdef ENABLE_NFCONV
|
||||
if(nfconvert_utf8 && (t - *outs) > 0) {
|
||||
if ( nfconvert_utf8 && ( t - *outs ) > 0 )
|
||||
{
|
||||
char *new_outs = NULL;
|
||||
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(original_outs_value != *outs) {
|
||||
if ( new_outs_len >= 0 && new_outs != NULL )
|
||||
{
|
||||
if ( original_outs_value != *outs )
|
||||
{
|
||||
// We have allocated outs ourselves.
|
||||
free( *outs );
|
||||
*outs = new_outs;
|
||||
t = *outs + new_outs_len;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// We need to copy new_outs into the fixed outs buffer.
|
||||
memset( *outs, 0, original_outs_len );
|
||||
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 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
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_len=%d\n", new_outs_len );
|
||||
@ -626,11 +671,14 @@ static int utf8_to_utf16_size(const char *s)
|
||||
unsigned int byte;
|
||||
size_t count = 0;
|
||||
|
||||
while ((byte = *((const unsigned char *)s++))) {
|
||||
while ( ( byte = *( ( const unsigned char * )s++ ) ) )
|
||||
{
|
||||
if ( ++count >= PATH_MAX )
|
||||
goto fail;
|
||||
if (byte >= 0xc0) {
|
||||
if (byte >= 0xF5) {
|
||||
if ( byte >= 0xc0 )
|
||||
{
|
||||
if ( byte >= 0xF5 )
|
||||
{
|
||||
errno = EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
@ -644,7 +692,8 @@ static int utf8_to_utf16_size(const char *s)
|
||||
s++;
|
||||
if ( !*s )
|
||||
break;
|
||||
if (byte >= 0xF0) {
|
||||
if ( byte >= 0xF0 )
|
||||
{
|
||||
s++;
|
||||
if ( ++count >= PATH_MAX )
|
||||
goto fail;
|
||||
@ -670,25 +719,37 @@ static int utf8_to_unicode(u32 *wc, const char *s)
|
||||
unsigned int byte = *( ( const unsigned char * )s );
|
||||
|
||||
/* single byte */
|
||||
if (byte == 0) {
|
||||
if ( byte == 0 )
|
||||
{
|
||||
*wc = ( u32 ) 0;
|
||||
return 0;
|
||||
} else if (byte < 0x80) {
|
||||
}
|
||||
else if ( byte < 0x80 )
|
||||
{
|
||||
*wc = ( u32 ) byte;
|
||||
return 1;
|
||||
/* double byte */
|
||||
} else if (byte < 0xc2) {
|
||||
}
|
||||
else if ( byte < 0xc2 )
|
||||
{
|
||||
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 )
|
||||
| ( ( u32 )( s[1] & 0x3F ) );
|
||||
return 2;
|
||||
} else
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
/* 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 )
|
||||
| ( ( u32 )( s[1] & 0x3F ) << 6 )
|
||||
| ( ( u32 )( s[2] & 0x3F ) );
|
||||
@ -705,9 +766,12 @@ static int utf8_to_unicode(u32 *wc, const char *s)
|
||||
}
|
||||
goto fail;
|
||||
/* four-byte */
|
||||
} else if (byte < 0xF5) {
|
||||
}
|
||||
else if ( byte < 0xF5 )
|
||||
{
|
||||
if ( ( ( s[1] & 0xC0 ) == 0x80 ) && ( ( s[2] & 0xC0 ) == 0x80 )
|
||||
&& ((s[3] & 0xC0) == 0x80)) {
|
||||
&& ( ( s[3] & 0xC0 ) == 0x80 ) )
|
||||
{
|
||||
*wc = ( ( u32 )( byte & 0x07 ) << 18 )
|
||||
| ( ( u32 )( s[1] & 0x3F ) << 12 )
|
||||
| ( ( 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__)
|
||||
#ifdef ENABLE_NFCONV
|
||||
char *new_ins = NULL;
|
||||
if(nfconvert_utf8) {
|
||||
if ( nfconvert_utf8 )
|
||||
{
|
||||
int new_ins_len;
|
||||
new_ins_len = ntfs_macosx_normalize_utf8( ins, &new_ins, 1 ); // Normalize to composed form
|
||||
if ( new_ins_len >= 0 )
|
||||
@ -757,7 +822,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
||||
goto fail;
|
||||
|
||||
allocated = FALSE;
|
||||
if (!*outs) {
|
||||
if ( !*outs )
|
||||
{
|
||||
*outs = ntfs_malloc( ( shorts + 1 ) * sizeof( ntfschar ) );
|
||||
if ( !*outs )
|
||||
goto fail;
|
||||
@ -766,12 +832,16 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
||||
|
||||
outpos = *outs;
|
||||
|
||||
while(1) {
|
||||
while ( 1 )
|
||||
{
|
||||
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 */
|
||||
if (allocated) {
|
||||
if ( allocated )
|
||||
{
|
||||
free( *outs );
|
||||
*outs = ( ntfschar* )NULL;
|
||||
}
|
||||
@ -782,7 +852,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
||||
}
|
||||
if ( wc < 0x10000 )
|
||||
*outpos++ = cpu_to_le16( wc );
|
||||
else {
|
||||
else
|
||||
{
|
||||
wc -= 0x10000;
|
||||
*outpos++ = cpu_to_le16( ( wc >> 10 ) + 0xd800 );
|
||||
*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;
|
||||
#endif
|
||||
|
||||
if (!ins || !outs) {
|
||||
if ( !ins || !outs )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
mbs = *outs;
|
||||
mbs_len = outs_len;
|
||||
if (mbs && !mbs_len) {
|
||||
if ( mbs && !mbs_len )
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if ( use_utf8 )
|
||||
return ntfs_utf16_to_utf8( ins, ins_len, outs, outs_len );
|
||||
if (!mbs) {
|
||||
if ( !mbs )
|
||||
{
|
||||
mbs_len = ( ins_len + 1 ) * MB_CUR_MAX;
|
||||
mbs = ntfs_malloc( mbs_len );
|
||||
if ( !mbs )
|
||||
@ -860,11 +934,14 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
#else
|
||||
wctomb( NULL, 0 );
|
||||
#endif
|
||||
for (i = o = 0; i < ins_len; i++) {
|
||||
for ( i = o = 0; i < ins_len; i++ )
|
||||
{
|
||||
/* Reallocate memory if necessary or abort. */
|
||||
if ((int)(o + MB_CUR_MAX) > mbs_len) {
|
||||
if ( ( int )( o + MB_CUR_MAX ) > mbs_len )
|
||||
{
|
||||
char *tc;
|
||||
if (mbs == *outs) {
|
||||
if ( mbs == *outs )
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
@ -888,7 +965,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
#endif
|
||||
if ( cnt == -1 )
|
||||
goto err_out;
|
||||
if (cnt <= 0) {
|
||||
if ( cnt <= 0 )
|
||||
{
|
||||
ntfs_log_debug( "Eeek. cnt <= 0, cnt = %i\n", cnt );
|
||||
errno = EINVAL;
|
||||
goto err_out;
|
||||
@ -897,7 +975,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
}
|
||||
#ifdef HAVE_MBSINIT
|
||||
/* 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" );
|
||||
errno = EILSEQ;
|
||||
goto err_out;
|
||||
@ -909,7 +988,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
*outs = mbs;
|
||||
return o;
|
||||
err_out:
|
||||
if (mbs != *outs) {
|
||||
if ( mbs != *outs )
|
||||
{
|
||||
int eo = errno;
|
||||
free( mbs );
|
||||
errno = eo;
|
||||
@ -950,7 +1030,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
mbstate_t mbstate;
|
||||
#endif
|
||||
|
||||
if (!ins || !outs) {
|
||||
if ( !ins || !outs )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -966,7 +1047,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
memset( &mbstate, 0, sizeof( mbstate ) );
|
||||
ins_len = mbsrtowcs( NULL, ( const char ** ) & s, 0, &mbstate );
|
||||
#ifdef __CYGWIN32__
|
||||
if (!ins_len && *ins) {
|
||||
if ( !ins_len && *ins )
|
||||
{
|
||||
/* Older Cygwin had broken mbsrtowcs() implementation. */
|
||||
ins_len = strlen( ins );
|
||||
}
|
||||
@ -980,9 +1062,11 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
if ( ins_len == -1 )
|
||||
return ins_len;
|
||||
#ifdef HAVE_MBSINIT
|
||||
if ((s != ins) || !mbsinit(&mbstate)) {
|
||||
if ( ( s != ins ) || !mbsinit( &mbstate ) )
|
||||
{
|
||||
#else
|
||||
if (s != ins) {
|
||||
if ( s != ins )
|
||||
{
|
||||
#endif
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
@ -998,9 +1082,11 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
#else
|
||||
mbtowc( NULL, NULL, 0 );
|
||||
#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. */
|
||||
if (o >= ucs_len) {
|
||||
if ( o >= ucs_len )
|
||||
{
|
||||
ntfschar *tc;
|
||||
ucs_len = ( ucs_len * sizeof( ntfschar ) + 64 ) & ~63;
|
||||
tc = realloc( ucs, ucs_len );
|
||||
@ -1019,14 +1105,16 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
break;
|
||||
if ( cnt == -1 )
|
||||
goto err_out;
|
||||
if (cnt < -1) {
|
||||
if ( cnt < -1 )
|
||||
{
|
||||
ntfs_log_trace( "Eeek. cnt = %i\n", cnt );
|
||||
errno = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
/* Make sure we are not overflowing the NTFS Unicode set. */
|
||||
if ( ( unsigned long )wc >= ( unsigned long )( 1 <<
|
||||
(8 * sizeof(ntfschar)))) {
|
||||
( 8 * sizeof( ntfschar ) ) ) )
|
||||
{
|
||||
errno = EILSEQ;
|
||||
goto err_out;
|
||||
}
|
||||
@ -1035,7 +1123,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
}
|
||||
#ifdef HAVE_MBSINIT
|
||||
/* 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" );
|
||||
errno = EILSEQ;
|
||||
goto err_out;
|
||||
@ -1069,24 +1158,32 @@ char *ntfs_uppercase_mbs(const char *low,
|
||||
|
||||
size = strlen( low );
|
||||
upp = ( char* )ntfs_malloc( 3 * size + 1 );
|
||||
if (upp) {
|
||||
if ( upp )
|
||||
{
|
||||
s = low;
|
||||
t = upp;
|
||||
do {
|
||||
do
|
||||
{
|
||||
n = utf8_to_unicode( &wc, s );
|
||||
if (n > 0) {
|
||||
if ( n > 0 )
|
||||
{
|
||||
if ( wc < upcase_size )
|
||||
wc = le16_to_cpu( upcase[wc] );
|
||||
if ( wc < 0x80 )
|
||||
*t++ = wc;
|
||||
else if (wc < 0x800) {
|
||||
else if ( wc < 0x800 )
|
||||
{
|
||||
*t++ = ( 0xc0 | ( ( wc >> 6 ) & 0x3f ) );
|
||||
*t++ = 0x80 | ( wc & 0x3f );
|
||||
} else if (wc < 0x10000) {
|
||||
}
|
||||
else if ( wc < 0x10000 )
|
||||
{
|
||||
*t++ = 0xe0 | ( wc >> 12 );
|
||||
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
|
||||
*t++ = 0x80 | ( wc & 0x3f );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
*t++ = 0xf0 | ( ( wc >> 18 ) & 7 );
|
||||
*t++ = 0x80 | ( ( wc >> 12 ) & 63 );
|
||||
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
|
||||
@ -1094,8 +1191,10 @@ char *ntfs_uppercase_mbs(const char *low,
|
||||
}
|
||||
s += n;
|
||||
}
|
||||
} while (n > 0);
|
||||
if (n < 0) {
|
||||
}
|
||||
while ( n > 0 );
|
||||
if ( n < 0 )
|
||||
{
|
||||
free( upp );
|
||||
upp = ( char* )NULL;
|
||||
errno = EILSEQ;
|
||||
@ -1117,7 +1216,8 @@ char *ntfs_uppercase_mbs(const char *low,
|
||||
*/
|
||||
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},
|
||||
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
||||
{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},
|
||||
{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},
|
||||
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
|
||||
{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},
|
||||
{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},
|
||||
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
|
||||
{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;
|
||||
for ( i = 0; ( u32 )i < uc_len; 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];
|
||||
for ( i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++ )
|
||||
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 ( i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2 )
|
||||
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];
|
||||
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;
|
||||
|
||||
lc = ( ntfschar* )ntfs_malloc( uc_cnt * sizeof( ntfschar ) );
|
||||
if (lc) {
|
||||
if ( lc )
|
||||
{
|
||||
for ( i = 0; i < uc_cnt; 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] );
|
||||
if ( ( upp != i ) && ( upp < uc_cnt ) )
|
||||
lc[upp] = cpu_to_le16( i );
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
ntfs_log_error( "Could not build the locase table\n" );
|
||||
return ( lc );
|
||||
}
|
||||
@ -1229,16 +1336,19 @@ ntfschar *ntfs_str2ucs(const char *s, int *len)
|
||||
{
|
||||
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 );
|
||||
return NULL;
|
||||
}
|
||||
if (*len > NTFS_MAX_NAME_LEN) {
|
||||
if ( *len > NTFS_MAX_NAME_LEN )
|
||||
{
|
||||
free( ucs );
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
if (!ucs || !*len) {
|
||||
if ( !ucs || !*len )
|
||||
{
|
||||
ucs = AT_UNNAMED;
|
||||
*len = 0;
|
||||
}
|
||||
@ -1282,7 +1392,8 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
||||
forbidden = ( len == 0 )
|
||||
|| ( 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] );
|
||||
if ( ( ch < 0x20 )
|
||||
|| ( ( ch < 0x40 )
|
||||
@ -1314,7 +1425,8 @@ BOOL ntfs_collapsible_chars(ntfs_volume *vol,
|
||||
|
||||
collapsible = shortlen == longlen;
|
||||
if ( collapsible )
|
||||
for (i=0; i<shortlen; i++) {
|
||||
for ( i = 0; i < shortlen; i++ )
|
||||
{
|
||||
ch = le16_to_cpu( longname[i] );
|
||||
if ( ( ch >= vol->upcase_len )
|
||||
|| ( ( shortname[i] != longname[i] )
|
||||
@ -1335,10 +1447,10 @@ int ntfs_set_char_encoding(const char *locale)
|
||||
if ( !locale || strstr( locale, "utf8" ) || strstr( locale, "UTF8" )
|
||||
|| strstr( locale, "utf-8" ) || strstr( locale, "UTF-8" ) )
|
||||
use_utf8 = 1;
|
||||
else
|
||||
if (setlocale(LC_ALL, locale))
|
||||
else if ( setlocale( LC_ALL, locale ) )
|
||||
use_utf8 = 0;
|
||||
else {
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Invalid locale, encoding to UTF-8\n" );
|
||||
use_utf8 = 1;
|
||||
}
|
||||
@ -1347,9 +1459,11 @@ int ntfs_set_char_encoding(const char *locale)
|
||||
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
|
||||
int ntfs_macosx_normalize_filenames(int normalize) {
|
||||
int ntfs_macosx_normalize_filenames( int normalize )
|
||||
{
|
||||
#ifdef ENABLE_NFCONV
|
||||
if(normalize == 0 || normalize == 1) {
|
||||
if ( normalize == 0 || normalize == 1 )
|
||||
{
|
||||
nfconvert_utf8 = normalize;
|
||||
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 composed) {
|
||||
int composed )
|
||||
{
|
||||
#ifdef ENABLE_NFCONV
|
||||
/* For this code to compile, the CoreFoundation framework must be fed to the linker. */
|
||||
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. */
|
||||
cfSourceString = CFStringCreateWithCString( kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8 );
|
||||
if(cfSourceString == NULL) {
|
||||
if ( cfSourceString == NULL )
|
||||
{
|
||||
ntfs_log_error( "CFStringCreateWithCString failed!\n" );
|
||||
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. */
|
||||
cfMutableString = CFStringCreateMutableCopy( kCFAllocatorDefault, 0, cfSourceString );
|
||||
CFRelease( cfSourceString ); /* End-of-life. */
|
||||
if(cfMutableString == NULL) {
|
||||
if ( cfMutableString == NULL )
|
||||
{
|
||||
ntfs_log_error( "CFStringCreateMutableCopy failed!\n" );
|
||||
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. */
|
||||
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 );
|
||||
result = ntfs_calloc( resultLength );
|
||||
|
||||
if(result != NULL) {
|
||||
if ( result != NULL )
|
||||
{
|
||||
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" );
|
||||
free( result );
|
||||
result = NULL;
|
||||
@ -1412,7 +1532,8 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
|
||||
|
||||
CFRelease( cfMutableString );
|
||||
|
||||
if(result != NULL) {
|
||||
if ( result != NULL )
|
||||
{
|
||||
*target = result;
|
||||
return resultLength - 1;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user