mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-12-19 00:11:55 +01:00
* remove little unused code
* code cleanup
This commit is contained in:
parent
e1a36e8988
commit
9e79c9d99b
@ -2,8 +2,8 @@
|
|||||||
<app version="1">
|
<app version="1">
|
||||||
<name> USB Loader GX</name>
|
<name> USB Loader GX</name>
|
||||||
<coder>USB Loader GX Team</coder>
|
<coder>USB Loader GX Team</coder>
|
||||||
<version>1.0 r950</version>
|
<version>1.0 r951</version>
|
||||||
<release_date>201009182245</release_date>
|
<release_date>201009182308</release_date>
|
||||||
<short_description>Loads games from USB-devices</short_description>
|
<short_description>Loads games from USB-devices</short_description>
|
||||||
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
||||||
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||||
|
BIN
data/magic_patcher.o
Normal file
BIN
data/magic_patcher.o
Normal file
Binary file not shown.
@ -37,7 +37,8 @@
|
|||||||
*
|
*
|
||||||
* Font face character glyph relevant data structure.
|
* Font face character glyph relevant data structure.
|
||||||
*/
|
*/
|
||||||
typedef struct ftgxCharData_ {
|
typedef struct ftgxCharData_
|
||||||
|
{
|
||||||
int16_t renderOffsetX; /**< Texture X axis bearing offset. */
|
int16_t renderOffsetX; /**< Texture X axis bearing offset. */
|
||||||
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
|
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
|
||||||
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
|
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
|
||||||
@ -56,7 +57,8 @@ typedef struct ftgxCharData_ {
|
|||||||
*
|
*
|
||||||
* Offset structure which hold both a maximum and minimum value.
|
* Offset structure which hold both a maximum and minimum value.
|
||||||
*/
|
*/
|
||||||
typedef struct ftgxDataOffset_ {
|
typedef struct ftgxDataOffset_
|
||||||
|
{
|
||||||
int16_t ascender; /**< Maximum data offset. */
|
int16_t ascender; /**< Maximum data offset. */
|
||||||
int16_t descender; /**< Minimum data offset. */
|
int16_t descender; /**< Minimum data offset. */
|
||||||
int16_t max; /**< Maximum data offset. */
|
int16_t max; /**< Maximum data offset. */
|
||||||
|
@ -121,7 +121,8 @@ bool ZipFile::ExtractAll(const char *dest)
|
|||||||
|
|
||||||
done += ret;
|
done += ret;
|
||||||
|
|
||||||
} while(done < uncompressed_size);
|
}
|
||||||
|
while ( done < uncompressed_size );
|
||||||
|
|
||||||
fclose( pfile );
|
fclose( pfile );
|
||||||
unzCloseCurrentFile( File );
|
unzCloseCurrentFile( File );
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
*
|
*
|
||||||
* Initializes the Wii's audio subsystem
|
* Initializes the Wii's audio subsystem
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
void InitAudio() {
|
void InitAudio()
|
||||||
|
{
|
||||||
AUDIO_Init( NULL );
|
AUDIO_Init( NULL );
|
||||||
ASND_Init();
|
ASND_Init();
|
||||||
ASND_Pause( 0 );
|
ASND_Pause( 0 );
|
||||||
@ -27,7 +28,8 @@ void InitAudio() {
|
|||||||
* Shuts down audio subsystem. Useful to avoid unpleasant sounds if a
|
* Shuts down audio subsystem. Useful to avoid unpleasant sounds if a
|
||||||
* crash occurs during shutdown.
|
* crash occurs during shutdown.
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
void ShutdownAudio() {
|
void ShutdownAudio()
|
||||||
|
{
|
||||||
ASND_Pause( 1 );
|
ASND_Pause( 1 );
|
||||||
ASND_End();
|
ASND_End();
|
||||||
}
|
}
|
||||||
|
@ -552,7 +552,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
|||||||
|
|
||||||
file = fopen( src, "rb" );
|
file = fopen( src, "rb" );
|
||||||
|
|
||||||
if (file==NULL){
|
if ( file == NULL )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,7 +570,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
|||||||
|
|
||||||
unsigned char * buffer = malloc( blksize );
|
unsigned char * buffer = malloc( blksize );
|
||||||
|
|
||||||
if(buffer == NULL){
|
if ( buffer == NULL )
|
||||||
|
{
|
||||||
//no memory
|
//no memory
|
||||||
fclose( file );
|
fclose( file );
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -580,7 +582,8 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
|||||||
read = fread( buffer, 1, blksize, file );
|
read = fread( buffer, 1, blksize, file );
|
||||||
( void )auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
|
( void )auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
|
||||||
|
|
||||||
} while(read > 0);
|
}
|
||||||
|
while ( read > 0 );
|
||||||
|
|
||||||
fclose( file );
|
fclose( file );
|
||||||
free( buffer );
|
free( buffer );
|
||||||
|
@ -39,7 +39,8 @@ s32 dump_banner(const u8* discid,const char * dest)
|
|||||||
|
|
||||||
ret = WDVD_OpenPartition( offset );
|
ret = WDVD_OpenPartition( offset );
|
||||||
|
|
||||||
if (ret < 0) {
|
if ( ret < 0 )
|
||||||
|
{
|
||||||
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
|||||||
|
|
||||||
FILE *tplfp = fopen( tplfilepath, "rb" );
|
FILE *tplfp = fopen( tplfilepath, "rb" );
|
||||||
|
|
||||||
if(tplfp !=NULL) {
|
if ( tplfp != NULL )
|
||||||
|
{
|
||||||
|
|
||||||
unsigned short heighttemp = 0;
|
unsigned short heighttemp = 0;
|
||||||
unsigned short widthtemp = 0;
|
unsigned short widthtemp = 0;
|
||||||
@ -27,7 +28,8 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
|||||||
tplfilesize = ftell ( tplfp );
|
tplfilesize = ftell ( tplfp );
|
||||||
rewind ( tplfp );
|
rewind ( tplfp );
|
||||||
memory = memalign( 32, tplfilesize );
|
memory = memalign( 32, tplfilesize );
|
||||||
if(!memory) {
|
if ( !memory )
|
||||||
|
{
|
||||||
fclose( tplfp );
|
fclose( tplfp );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -38,13 +40,15 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
||||||
if(ret < 0) {
|
if ( ret < 0 )
|
||||||
|
{
|
||||||
free( memory );
|
free( memory );
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
||||||
if(ret < 0) {
|
if ( ret < 0 )
|
||||||
|
{
|
||||||
free( memory );
|
free( memory );
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
@ -56,7 +60,9 @@ GuiBanner::GuiBanner(const char *tplfilepath)
|
|||||||
widescreen = 0;
|
widescreen = 0;
|
||||||
filecheck = true;
|
filecheck = true;
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
filecheck = false;
|
filecheck = false;
|
||||||
fclose( tplfp );
|
fclose( tplfp );
|
||||||
}
|
}
|
||||||
@ -76,13 +82,15 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
||||||
if(ret < 0) {
|
if ( ret < 0 )
|
||||||
|
{
|
||||||
free( memory );
|
free( memory );
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
||||||
if(ret < 0) {
|
if ( ret < 0 )
|
||||||
|
{
|
||||||
free( memory );
|
free( memory );
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
@ -94,7 +102,8 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
|||||||
|
|
||||||
GuiBanner::~GuiBanner()
|
GuiBanner::~GuiBanner()
|
||||||
{
|
{
|
||||||
if(memory != NULL) {
|
if ( memory != NULL )
|
||||||
|
{
|
||||||
free( memory );
|
free( memory );
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,8 @@ void md5(u8 *data, u32 len, u8 *hash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 zeroes[0x40];
|
u8 zeroes[0x40];
|
||||||
u32 imet; // "IMET"
|
u32 imet; // "IMET"
|
||||||
u8 zero_six_zero_three[8]; // fixed, unknown purpose
|
u8 zero_six_zero_three[8]; // fixed, unknown purpose
|
||||||
@ -89,7 +90,8 @@ typedef struct {
|
|||||||
u8 crypto[0x10];
|
u8 crypto[0x10];
|
||||||
} imet_data_t;
|
} imet_data_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 imd5_tag; // 0x494D4435 "IMD5";
|
u32 imd5_tag; // 0x494D4435 "IMD5";
|
||||||
u32 size; // size of the rest of part B, starting from next field.
|
u32 size; // size of the rest of part B, starting from next field.
|
||||||
u8 zeroes[8];
|
u8 zeroes[8];
|
||||||
@ -148,13 +150,16 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
|||||||
|
|
||||||
out_ptr = decompressed_data;
|
out_ptr = decompressed_data;
|
||||||
|
|
||||||
while (in_ptr < data_end) {
|
while ( in_ptr < data_end )
|
||||||
|
{
|
||||||
int bit;
|
int bit;
|
||||||
u8 bitmask = *in_ptr;
|
u8 bitmask = *in_ptr;
|
||||||
|
|
||||||
in_ptr++;
|
in_ptr++;
|
||||||
for (bit = 0x80; bit != 0; bit >>= 1) {
|
for ( bit = 0x80; bit != 0; bit >>= 1 )
|
||||||
if (bitmask & bit) {
|
{
|
||||||
|
if ( bitmask & bit )
|
||||||
|
{
|
||||||
// Next section is compressed
|
// Next section is compressed
|
||||||
u8 rep_length;
|
u8 rep_length;
|
||||||
u16 rep_offset;
|
u16 rep_offset;
|
||||||
@ -164,14 +169,17 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
|||||||
in_ptr++;
|
in_ptr++;
|
||||||
rep_offset = *in_ptr | ( rep_offset << 8 );
|
rep_offset = *in_ptr | ( rep_offset << 8 );
|
||||||
in_ptr++;
|
in_ptr++;
|
||||||
if (out_ptr-decompressed_data < rep_offset) {
|
if ( out_ptr - decompressed_data < rep_offset )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( ; rep_length > 0; rep_length--) {
|
for ( ; rep_length > 0; rep_length-- )
|
||||||
|
{
|
||||||
*out_ptr = out_ptr[-rep_offset-1];
|
*out_ptr = out_ptr[-rep_offset-1];
|
||||||
out_ptr++;
|
out_ptr++;
|
||||||
if (out_ptr >= out_end) {
|
if ( out_ptr >= out_end )
|
||||||
|
{
|
||||||
// Need to grow buffer
|
// Need to grow buffer
|
||||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||||
out_ptr = decompressed_data + unpacked_size;
|
out_ptr = decompressed_data + unpacked_size;
|
||||||
@ -179,11 +187,14 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
|||||||
out_end = decompressed_data + unpacked_size;
|
out_end = decompressed_data + unpacked_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Just copy byte
|
// Just copy byte
|
||||||
*out_ptr = *in_ptr;
|
*out_ptr = *in_ptr;
|
||||||
out_ptr++;
|
out_ptr++;
|
||||||
if (out_ptr >= out_end) {
|
if ( out_ptr >= out_end )
|
||||||
|
{
|
||||||
// Need to grow buffer
|
// Need to grow buffer
|
||||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||||
out_ptr = decompressed_data + unpacked_size;
|
out_ptr = decompressed_data + unpacked_size;
|
||||||
@ -209,22 +220,26 @@ static int write_imd5_lz77(u8* data, size_t size, char* outname)
|
|||||||
size_t decompressed_size;
|
size_t decompressed_size;
|
||||||
|
|
||||||
tag = be32( ( u8* ) & header->imd5_tag );
|
tag = be32( ( u8* ) & header->imd5_tag );
|
||||||
if (tag != 0x494D4435) {
|
if ( tag != 0x494D4435 )
|
||||||
|
{
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
md5( data + 32, size - 32, md5_calc );
|
md5( data + 32, size - 32, md5_calc );
|
||||||
if (memcmp(&header->md5, md5_calc, 0x10)) {
|
if ( memcmp( &header->md5, md5_calc, 0x10 ) )
|
||||||
|
{
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_in_imd5 = be32( ( u8* ) & header->size );
|
size_in_imd5 = be32( ( u8* ) & header->size );
|
||||||
if (size_in_imd5 != size - 32) {
|
if ( size_in_imd5 != size - 32 )
|
||||||
|
{
|
||||||
return -6;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
tag = be32( ( u8* ) & header->payload_tag );
|
tag = be32( ( u8* ) & header->payload_tag );
|
||||||
if (tag == 0x4C5A3737) {
|
if ( tag == 0x4C5A3737 )
|
||||||
|
{
|
||||||
// "LZ77" - uncompress
|
// "LZ77" - uncompress
|
||||||
decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size );
|
decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size );
|
||||||
if ( decompressed_data == NULL )
|
if ( decompressed_data == NULL )
|
||||||
@ -233,7 +248,9 @@ static int write_imd5_lz77(u8* data, size_t size, char* outname)
|
|||||||
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
|
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
|
||||||
|
|
||||||
free( decompressed_data );
|
free( decompressed_data );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
write_file( &header->payload_tag, size - 32, outname );
|
write_file( &header->payload_tag, size - 32, outname );
|
||||||
//printf(", md5 ok");
|
//printf(", md5 ok");
|
||||||
}
|
}
|
||||||
@ -257,7 +274,8 @@ static int do_U8_archive(FILE *fp)
|
|||||||
|
|
||||||
fread( &header, 1, sizeof header, fp );
|
fread( &header, 1, sizeof header, fp );
|
||||||
tag = be32( ( u8* ) & header.tag );
|
tag = be32( ( u8* ) & header.tag );
|
||||||
if (tag != 0x55AA382D) {
|
if ( tag != 0x55AA382D )
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +293,8 @@ static int do_U8_archive(FILE *fp)
|
|||||||
fread( string_table, 1, rest_size, fp );
|
fread( string_table, 1, rest_size, fp );
|
||||||
current_offset = data_offset;
|
current_offset = data_offset;
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
for ( i = 0; i < num_nodes; i++ )
|
||||||
|
{
|
||||||
U8_node* node = &nodes[i];
|
U8_node* node = &nodes[i];
|
||||||
u16 type = be16( ( u8* ) & node->type );
|
u16 type = be16( ( u8* ) & node->type );
|
||||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
||||||
@ -284,25 +303,31 @@ static int do_U8_archive(FILE *fp)
|
|||||||
char* name = ( char* ) & string_table[name_offset];
|
char* name = ( char* ) & string_table[name_offset];
|
||||||
u8* file_data;
|
u8* file_data;
|
||||||
|
|
||||||
if (type == 0x0100) {
|
if ( type == 0x0100 )
|
||||||
|
{
|
||||||
// Directory
|
// Directory
|
||||||
mkdir( name, 0777 );
|
mkdir( name, 0777 );
|
||||||
chdir( name );
|
chdir( name );
|
||||||
dir_stack[++dir_index] = size;
|
dir_stack[++dir_index] = size;
|
||||||
//printf("%*s%s/\n", dir_index, "", name);
|
//printf("%*s%s/\n", dir_index, "", name);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Normal file
|
// Normal file
|
||||||
u8 padding[32];
|
u8 padding[32];
|
||||||
|
|
||||||
if (type != 0x0000) {
|
if ( type != 0x0000 )
|
||||||
|
{
|
||||||
free( string_table );
|
free( string_table );
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_offset < my_data_offset) {
|
if ( current_offset < my_data_offset )
|
||||||
|
{
|
||||||
int diff = my_data_offset - current_offset;
|
int diff = my_data_offset - current_offset;
|
||||||
|
|
||||||
if (diff > 32) {
|
if ( diff > 32 )
|
||||||
|
{
|
||||||
free( string_table );
|
free( string_table );
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
@ -316,14 +341,16 @@ static int do_U8_archive(FILE *fp)
|
|||||||
int result;
|
int result;
|
||||||
result = write_imd5_lz77( file_data, size, name );
|
result = write_imd5_lz77( file_data, size, name );
|
||||||
if ( result < 0 )
|
if ( result < 0 )
|
||||||
{free(string_table);
|
{
|
||||||
|
free( string_table );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
//printf(")\n");
|
//printf(")\n");
|
||||||
current_offset += size;
|
current_offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dir_stack[dir_index] == i+2 && dir_index > 0) {
|
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
||||||
|
{
|
||||||
chdir( ".." );
|
chdir( ".." );
|
||||||
dir_index--;
|
dir_index--;
|
||||||
}
|
}
|
||||||
@ -357,7 +384,8 @@ void do_U8_archivebanner(FILE *fp)
|
|||||||
|
|
||||||
fread( &header, 1, sizeof header, fp );
|
fread( &header, 1, sizeof header, fp );
|
||||||
tag = be32( ( u8* ) & header.tag );
|
tag = be32( ( u8* ) & header.tag );
|
||||||
if (tag != 0x55AA382D) {
|
if ( tag != 0x55AA382D )
|
||||||
|
{
|
||||||
//printf("No U8 tag");
|
//printf("No U8 tag");
|
||||||
exit( 0 );
|
exit( 0 );
|
||||||
}
|
}
|
||||||
@ -375,7 +403,8 @@ void do_U8_archivebanner(FILE *fp)
|
|||||||
string_table = malloc( rest_size );
|
string_table = malloc( rest_size );
|
||||||
fread( string_table, 1, rest_size, fp );
|
fread( string_table, 1, rest_size, fp );
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
for ( i = 0; i < num_nodes; i++ )
|
||||||
|
{
|
||||||
U8_node* node = &nodes[i];
|
U8_node* node = &nodes[i];
|
||||||
u16 type = be16( ( u8* ) & node->type );
|
u16 type = be16( ( u8* ) & node->type );
|
||||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
||||||
@ -384,16 +413,20 @@ void do_U8_archivebanner(FILE *fp)
|
|||||||
char* name = ( char* ) & string_table[name_offset];
|
char* name = ( char* ) & string_table[name_offset];
|
||||||
u8* file_data;
|
u8* file_data;
|
||||||
|
|
||||||
if (type == 0x0100) {
|
if ( type == 0x0100 )
|
||||||
|
{
|
||||||
// Directory
|
// Directory
|
||||||
mkdir( name, 0777 );
|
mkdir( name, 0777 );
|
||||||
chdir( name );
|
chdir( name );
|
||||||
dir_stack[++dir_index] = size;
|
dir_stack[++dir_index] = size;
|
||||||
//printf("%*s%s/\n", dir_index, "", name);
|
//printf("%*s%s/\n", dir_index, "", name);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Normal file
|
// Normal file
|
||||||
|
|
||||||
if (type != 0x0000) {
|
if ( type != 0x0000 )
|
||||||
|
{
|
||||||
printf( "Unknown type" );
|
printf( "Unknown type" );
|
||||||
exit( 0 );
|
exit( 0 );
|
||||||
}
|
}
|
||||||
@ -406,7 +439,8 @@ void do_U8_archivebanner(FILE *fp)
|
|||||||
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
|
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dir_stack[dir_index] == i+2 && dir_index > 0) {
|
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
||||||
|
{
|
||||||
chdir( ".." );
|
chdir( ".." );
|
||||||
dir_index--;
|
dir_index--;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,8 @@ extern GuiWindow * mainWindow;
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* CheatMenu
|
* CheatMenu
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
int CheatMenu(const char * gameID) {
|
int CheatMenu( const char * gameID )
|
||||||
|
{
|
||||||
int choice = 0;
|
int choice = 0;
|
||||||
bool exit = false;
|
bool exit = false;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
@ -65,7 +66,8 @@ int CheatMenu(const char * gameID) {
|
|||||||
|
|
||||||
int download = 0;
|
int download = 0;
|
||||||
|
|
||||||
switch (check) {
|
switch ( check )
|
||||||
|
{
|
||||||
case -1:
|
case -1:
|
||||||
WindowPrompt( tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ) );
|
WindowPrompt( tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ) );
|
||||||
break;
|
break;
|
||||||
@ -92,7 +94,8 @@ int CheatMenu(const char * gameID) {
|
|||||||
titleTxt.SetMaxWidth( 350, SCROLL_HORIZONTAL );
|
titleTxt.SetMaxWidth( 350, SCROLL_HORIZONTAL );
|
||||||
titleTxt.SetPosition( 12, 40 );
|
titleTxt.SetPosition( 12, 40 );
|
||||||
|
|
||||||
for (int i = 0; i <= cntcheats; i++) {
|
for ( int i = 0; i <= cntcheats; i++ )
|
||||||
|
{
|
||||||
cheatslst.SetValue( i, "%s", c.getCheatName( i ).c_str() );
|
cheatslst.SetValue( i, "%s", c.getCheatName( i ).c_str() );
|
||||||
cheatslst.SetName( i, "OFF" );
|
cheatslst.SetName( i, "OFF" );
|
||||||
}
|
}
|
||||||
@ -109,34 +112,46 @@ int CheatMenu(const char * gameID) {
|
|||||||
mainWindow->Append( &w );
|
mainWindow->Append( &w );
|
||||||
ResumeGui();
|
ResumeGui();
|
||||||
|
|
||||||
while (!exit) {
|
while ( !exit )
|
||||||
|
{
|
||||||
VIDEO_WaitVSync ();
|
VIDEO_WaitVSync ();
|
||||||
|
|
||||||
ret = chtBrowser.GetClickedOption();
|
ret = chtBrowser.GetClickedOption();
|
||||||
if (ret != -1) {
|
if ( ret != -1 )
|
||||||
|
{
|
||||||
const char *strCheck = cheatslst.GetName( ret );
|
const char *strCheck = cheatslst.GetName( ret );
|
||||||
if (strncmp(strCheck,"ON",2) == 0) {
|
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
||||||
|
{
|
||||||
cheatslst.SetName( ret, "%s", "OFF" );
|
cheatslst.SetName( ret, "%s", "OFF" );
|
||||||
} else if (strncmp(strCheck,"OFF",3) == 0) {
|
}
|
||||||
|
else if ( strncmp( strCheck, "OFF", 3 ) == 0 )
|
||||||
|
{
|
||||||
cheatslst.SetName( ret, "%s", "ON" );
|
cheatslst.SetName( ret, "%s", "ON" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (createBtn.GetState() == STATE_CLICKED) {
|
if ( createBtn.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
createBtn.ResetState();
|
createBtn.ResetState();
|
||||||
if (cntcheats > 0) {
|
if ( cntcheats > 0 )
|
||||||
|
{
|
||||||
int selectednrs[30];
|
int selectednrs[30];
|
||||||
int x = 0;
|
int x = 0;
|
||||||
for (int i = 0; i <= cntcheats; i++) {
|
for ( int i = 0; i <= cntcheats; i++ )
|
||||||
|
{
|
||||||
const char *strCheck = cheatslst.GetName( i );
|
const char *strCheck = cheatslst.GetName( i );
|
||||||
if (strncmp(strCheck,"ON",2) == 0) {
|
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
||||||
|
{
|
||||||
selectednrs[x] = i;
|
selectednrs[x] = i;
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (x == 0) {
|
if ( x == 0 )
|
||||||
|
{
|
||||||
WindowPrompt( tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ) );
|
WindowPrompt( tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ) );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
subfoldercreate( Settings.Cheatcodespath );
|
subfoldercreate( Settings.Cheatcodespath );
|
||||||
string chtpath = Settings.Cheatcodespath;
|
string chtpath = Settings.Cheatcodespath;
|
||||||
string gctfname = chtpath + c.getGameID() + ".gct";
|
string gctfname = chtpath + c.getGameID() + ".gct";
|
||||||
@ -145,10 +160,12 @@ int CheatMenu(const char * gameID) {
|
|||||||
exit = true;
|
exit = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else WindowPrompt(tr("Error"),tr("Could not create GCT file"),tr("OK"));
|
}
|
||||||
|
else WindowPrompt( tr( "Error" ), tr( "Could not create GCT file" ), tr( "OK" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backBtn.GetState() == STATE_CLICKED) {
|
if ( backBtn.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
backBtn.ResetState();
|
backBtn.ResetState();
|
||||||
exit = true;
|
exit = true;
|
||||||
break;
|
break;
|
||||||
|
@ -12,11 +12,13 @@
|
|||||||
|
|
||||||
#define ERRORRANGE "Error: CheatNr out of range"
|
#define ERRORRANGE "Error: CheatNr out of range"
|
||||||
|
|
||||||
GCTCheats::GCTCheats(void) {
|
GCTCheats::GCTCheats( void )
|
||||||
|
{
|
||||||
iCntCheats = 0;
|
iCntCheats = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GCTCheats::~GCTCheats(void) {
|
GCTCheats::~GCTCheats( void )
|
||||||
|
{
|
||||||
|
|
||||||
string sGameID = "";
|
string sGameID = "";
|
||||||
string sGameTitle = "";
|
string sGameTitle = "";
|
||||||
@ -25,43 +27,59 @@ GCTCheats::~GCTCheats(void) {
|
|||||||
string sCheatComment[MAXCHEATS];*/
|
string sCheatComment[MAXCHEATS];*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::getCnt() {
|
int GCTCheats::getCnt()
|
||||||
|
{
|
||||||
return iCntCheats;
|
return iCntCheats;
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getGameName(void) {
|
string GCTCheats::getGameName( void )
|
||||||
|
{
|
||||||
return sGameTitle;
|
return sGameTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getGameID(void) {
|
string GCTCheats::getGameID( void )
|
||||||
|
{
|
||||||
return sGameID;
|
return sGameID;
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getCheat(int nr) {
|
string GCTCheats::getCheat( int nr )
|
||||||
if (nr <= (iCntCheats-1)) {
|
{
|
||||||
|
if ( nr <= ( iCntCheats - 1 ) )
|
||||||
|
{
|
||||||
return sCheats[nr];
|
return sCheats[nr];
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return ERRORRANGE;
|
return ERRORRANGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getCheatName(int nr) {
|
string GCTCheats::getCheatName( int nr )
|
||||||
if (nr <= (iCntCheats-1)) {
|
{
|
||||||
|
if ( nr <= ( iCntCheats - 1 ) )
|
||||||
|
{
|
||||||
return sCheatName[nr];
|
return sCheatName[nr];
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return ERRORRANGE;
|
return ERRORRANGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getCheatComment(int nr) {
|
string GCTCheats::getCheatComment( int nr )
|
||||||
if (nr <= (iCntCheats-1)) {
|
{
|
||||||
|
if ( nr <= ( iCntCheats - 1 ) )
|
||||||
|
{
|
||||||
return sCheatComment[nr];
|
return sCheatComment[nr];
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return ERRORRANGE;
|
return ERRORRANGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::createGCT(int nr,const char * filename) {
|
int GCTCheats::createGCT( int nr, const char * filename )
|
||||||
|
{
|
||||||
|
|
||||||
if ( nr == 0 )
|
if ( nr == 0 )
|
||||||
return 0;
|
return 0;
|
||||||
@ -83,7 +101,8 @@ int GCTCheats::createGCT(int nr,const char * filename) {
|
|||||||
long int li;
|
long int li;
|
||||||
int len = buf.size();
|
int len = buf.size();
|
||||||
|
|
||||||
while (x < len) {
|
while ( x < len )
|
||||||
|
{
|
||||||
string temp = buf.substr( x, 2 );
|
string temp = buf.substr( x, 2 );
|
||||||
li = strtol( temp.c_str(), NULL, 16 );
|
li = strtol( temp.c_str(), NULL, 16 );
|
||||||
temp = li;
|
temp = li;
|
||||||
@ -96,7 +115,8 @@ int GCTCheats::createGCT(int nr,const char * filename) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
int GCTCheats::createGCT( const char * chtbuffer, const char * filename )
|
||||||
|
{
|
||||||
|
|
||||||
ofstream filestr;
|
ofstream filestr;
|
||||||
filestr.open( filename );
|
filestr.open( filename );
|
||||||
@ -115,7 +135,8 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
|||||||
long int li;
|
long int li;
|
||||||
int len = buf.size();
|
int len = buf.size();
|
||||||
|
|
||||||
while (x < len) {
|
while ( x < len )
|
||||||
|
{
|
||||||
string temp = buf.substr( x, 2 );
|
string temp = buf.substr( x, 2 );
|
||||||
li = strtol( temp.c_str(), NULL, 16 );
|
li = strtol( temp.c_str(), NULL, 16 );
|
||||||
temp = li;
|
temp = li;
|
||||||
@ -130,7 +151,8 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
int GCTCheats::createGCT( int nr[], int cnt, const char * filename )
|
||||||
|
{
|
||||||
|
|
||||||
if ( cnt == 0 )
|
if ( cnt == 0 )
|
||||||
return 0;
|
return 0;
|
||||||
@ -148,14 +170,16 @@ int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
|||||||
filestr.write( header, sizeof( header ) );
|
filestr.write( header, sizeof( header ) );
|
||||||
|
|
||||||
int c = 0;
|
int c = 0;
|
||||||
while (c != cnt) {
|
while ( c != cnt )
|
||||||
|
{
|
||||||
int actnr = nr[c];
|
int actnr = nr[c];
|
||||||
string buf = getCheat( actnr );
|
string buf = getCheat( actnr );
|
||||||
long int li;
|
long int li;
|
||||||
int len = buf.size();
|
int len = buf.size();
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
|
||||||
while (x < len) {
|
while ( x < len )
|
||||||
|
{
|
||||||
string temp = buf.substr( x, 2 );
|
string temp = buf.substr( x, 2 );
|
||||||
li = strtol( temp.c_str(), NULL, 16 );
|
li = strtol( temp.c_str(), NULL, 16 );
|
||||||
temp = li;
|
temp = li;
|
||||||
@ -170,7 +194,8 @@ int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::openTxtfile(const char * filename) {
|
int GCTCheats::openTxtfile( const char * filename )
|
||||||
|
{
|
||||||
ifstream filestr;
|
ifstream filestr;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
string str;
|
string str;
|
||||||
@ -196,7 +221,8 @@ int GCTCheats::openTxtfile(const char * filename) {
|
|||||||
if ( !sGameTitle[sGameTitle.length() - 1] == '\r' )
|
if ( !sGameTitle[sGameTitle.length() - 1] == '\r' )
|
||||||
filestr.seekg( 0, ios_base::beg );
|
filestr.seekg( 0, ios_base::beg );
|
||||||
|
|
||||||
while (!filestr.eof()) {
|
while ( !filestr.eof() )
|
||||||
|
{
|
||||||
getline( filestr, sCheatName[i] ); // '\n' delimiter by default
|
getline( filestr, sCheatName[i] ); // '\n' delimiter by default
|
||||||
if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' )
|
if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' )
|
||||||
sCheatName[i].erase( sCheatName[i].length() - 1 );
|
sCheatName[i].erase( sCheatName[i].length() - 1 );
|
||||||
@ -204,31 +230,38 @@ int GCTCheats::openTxtfile(const char * filename) {
|
|||||||
string cheatdata;
|
string cheatdata;
|
||||||
bool emptyline = false;
|
bool emptyline = false;
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
getline( filestr, str );
|
getline( filestr, str );
|
||||||
if ( str[str.length() - 1] == '\r' )
|
if ( str[str.length() - 1] == '\r' )
|
||||||
str.erase( str.length() - 1 );
|
str.erase( str.length() - 1 );
|
||||||
|
|
||||||
if (str == "" || str[0] == '\r' || str[0] == '\n') {
|
if ( str == "" || str[0] == '\r' || str[0] == '\n' )
|
||||||
|
{
|
||||||
emptyline = true;
|
emptyline = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsCode(str)) {
|
if ( IsCode( str ) )
|
||||||
|
{
|
||||||
// remove any garbage (comment) after code
|
// remove any garbage (comment) after code
|
||||||
while (str.size() > 17) {
|
while ( str.size() > 17 )
|
||||||
|
{
|
||||||
str.erase( str.length() - 1 );
|
str.erase( str.length() - 1 );
|
||||||
}
|
}
|
||||||
cheatdata.append( str );
|
cheatdata.append( str );
|
||||||
size_t found = cheatdata.find( ' ' );
|
size_t found = cheatdata.find( ' ' );
|
||||||
cheatdata.replace( found, 1, "" );
|
cheatdata.replace( found, 1, "" );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
//printf("%i",str.size());
|
//printf("%i",str.size());
|
||||||
sCheatComment[i] = str;
|
sCheatComment[i] = str;
|
||||||
}
|
}
|
||||||
if ( filestr.eof() ) break;
|
if ( filestr.eof() ) break;
|
||||||
|
|
||||||
} while (!emptyline);
|
}
|
||||||
|
while ( !emptyline );
|
||||||
|
|
||||||
sCheats[i] = cheatdata;
|
sCheats[i] = cheatdata;
|
||||||
i++;
|
i++;
|
||||||
@ -239,14 +272,17 @@ int GCTCheats::openTxtfile(const char * filename) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCTCheats::IsCode(const std::string& str) {
|
bool GCTCheats::IsCode( const std::string& str )
|
||||||
if (str[8] == ' ' && str.size() >= 17) {
|
{
|
||||||
|
if ( str[8] == ' ' && str.size() >= 17 )
|
||||||
|
{
|
||||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||||
char part1[9];
|
char part1[9];
|
||||||
char part2[9];
|
char part2[9];
|
||||||
snprintf( part1, sizeof( part1 ), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7] );
|
snprintf( part1, sizeof( part1 ), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7] );
|
||||||
snprintf( part2, sizeof( part2 ), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14], str[15], str[16] );
|
snprintf( part2, sizeof( part2 ), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14], str[15], str[16] );
|
||||||
if ((strtok(part1,"0123456789ABCDEFabcdef") == NULL) && (strtok(part2,"0123456789ABCDEFabcdef") == NULL)) {
|
if ( ( strtok( part1, "0123456789ABCDEFabcdef" ) == NULL ) && ( strtok( part2, "0123456789ABCDEFabcdef" ) == NULL ) )
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
//!Handles Ocarina TXT Cheatfiles
|
//!Handles Ocarina TXT Cheatfiles
|
||||||
class GCTCheats {
|
class GCTCheats
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
string sGameID;
|
string sGameID;
|
||||||
string sGameTitle;
|
string sGameTitle;
|
||||||
|
@ -44,7 +44,8 @@ sec_t fat_wbfs_sec = 0;
|
|||||||
int fs_ntfs_mount = 0;
|
int fs_ntfs_mount = 0;
|
||||||
sec_t fs_ntfs_sec = 0;
|
sec_t fs_ntfs_sec = 0;
|
||||||
|
|
||||||
int USBDevice_Init() {
|
int USBDevice_Init()
|
||||||
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "\nUSBDevice_Init()" );
|
gprintf( "\nUSBDevice_Init()" );
|
||||||
#endif
|
#endif
|
||||||
@ -55,7 +56,8 @@ int USBDevice_Init() {
|
|||||||
//try first mount with cIOS
|
//try first mount with cIOS
|
||||||
// if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
// if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||||
// //try now mount with libogc
|
// //try now mount with libogc
|
||||||
if (!fatMount("USB", &__io_usbstorage2, 0, CACHE, SECTORS)) {
|
if ( !fatMount( "USB", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
||||||
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( ":-1" );
|
gprintf( ":-1" );
|
||||||
#endif
|
#endif
|
||||||
@ -71,7 +73,8 @@ int USBDevice_Init() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBDevice_deInit() {
|
void USBDevice_deInit()
|
||||||
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "\nUSBDevice_deInit()" );
|
gprintf( "\nUSBDevice_deInit()" );
|
||||||
#endif
|
#endif
|
||||||
@ -82,7 +85,8 @@ void USBDevice_deInit() {
|
|||||||
fat_usb_sec = 0;
|
fat_usb_sec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WBFSDevice_Init(u32 sector) {
|
int WBFSDevice_Init( u32 sector )
|
||||||
|
{
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "WBFS:/" );
|
fatUnmount( "WBFS:/" );
|
||||||
//right now mounts first FAT-partition
|
//right now mounts first FAT-partition
|
||||||
@ -90,21 +94,24 @@ int WBFSDevice_Init(u32 sector) {
|
|||||||
//try first mount with cIOS
|
//try first mount with cIOS
|
||||||
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||||
//try now mount with libogc
|
//try now mount with libogc
|
||||||
if (!fatMount("WBFS", &__io_usbstorage2, 0, CACHE, SECTORS)) {
|
if ( !fatMount( "WBFS", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fat_wbfs_mount = 1;
|
fat_wbfs_mount = 1;
|
||||||
fat_wbfs_sec = _FAT_startSector;
|
fat_wbfs_sec = _FAT_startSector;
|
||||||
if (sector && fat_wbfs_sec != sector) {
|
if ( sector && fat_wbfs_sec != sector )
|
||||||
|
{
|
||||||
// This is an error situation...actually, but is ignored in Config loader also
|
// This is an error situation...actually, but is ignored in Config loader also
|
||||||
// Should ask Oggzee about it...
|
// Should ask Oggzee about it...
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WBFSDevice_deInit() {
|
void WBFSDevice_deInit()
|
||||||
|
{
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "WBFS:/" );
|
fatUnmount( "WBFS:/" );
|
||||||
|
|
||||||
@ -112,21 +119,24 @@ void WBFSDevice_deInit() {
|
|||||||
fat_wbfs_sec = 0;
|
fat_wbfs_sec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isInserted(const char *path) {
|
int isInserted( const char *path )
|
||||||
|
{
|
||||||
if ( !strncmp( path, "USB:", 4 ) )
|
if ( !strncmp( path, "USB:", 4 ) )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return __io_sdhc.isInserted() || __io_wiisd.isInserted();
|
return __io_sdhc.isInserted() || __io_wiisd.isInserted();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDCard_Init() {
|
int SDCard_Init()
|
||||||
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "\nSDCard_Init()" );
|
gprintf( "\nSDCard_Init()" );
|
||||||
#endif
|
#endif
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "SD:/" );
|
fatUnmount( "SD:/" );
|
||||||
//right now mounts first FAT-partition
|
//right now mounts first FAT-partition
|
||||||
if (fatMount("SD", &__io_wiisd, 0, CACHE, SECTORS)) {
|
if ( fatMount( "SD", &__io_wiisd, 0, CACHE, SECTORS ) )
|
||||||
|
{
|
||||||
fat_sd_mount = MOUNT_SD;
|
fat_sd_mount = MOUNT_SD;
|
||||||
fat_sd_sec = _FAT_startSector;
|
fat_sd_sec = _FAT_startSector;
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
@ -134,7 +144,8 @@ int SDCard_Init() {
|
|||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (fatMount("SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE)) {
|
else if ( fatMount( "SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE ) )
|
||||||
|
{
|
||||||
fat_sd_mount = MOUNT_SDHC;
|
fat_sd_mount = MOUNT_SDHC;
|
||||||
fat_sd_sec = _FAT_startSector;
|
fat_sd_sec = _FAT_startSector;
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
@ -148,7 +159,8 @@ int SDCard_Init() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDCard_deInit() {
|
void SDCard_deInit()
|
||||||
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "\nSDCard_deInit()" );
|
gprintf( "\nSDCard_deInit()" );
|
||||||
#endif
|
#endif
|
||||||
@ -178,28 +190,37 @@ s32 MountNTFS(u32 sector)
|
|||||||
setlocale( LC_CTYPE, "C-UTF-8" );
|
setlocale( LC_CTYPE, "C-UTF-8" );
|
||||||
setlocale( LC_MESSAGES, "C-UTF-8" );
|
setlocale( LC_MESSAGES, "C-UTF-8" );
|
||||||
|
|
||||||
if (wbfsDev == WBFS_DEVICE_USB) {
|
if ( wbfsDev == WBFS_DEVICE_USB )
|
||||||
|
{
|
||||||
/* Initialize WBFS interface */
|
/* Initialize WBFS interface */
|
||||||
// if (!__io_wiiums.startup()) {
|
// if (!__io_wiiums.startup()) {
|
||||||
ret = __io_usbstorage2.startup();
|
ret = __io_usbstorage2.startup();
|
||||||
if (!ret) {
|
if ( !ret )
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
/* Mount device */
|
/* Mount device */
|
||||||
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||||
ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||||
if (!ret) {
|
if ( !ret )
|
||||||
|
{
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
} else if (wbfsDev == WBFS_DEVICE_SDHC) {
|
}
|
||||||
if (sdhc_mode_sd == 0) {
|
else if ( wbfsDev == WBFS_DEVICE_SDHC )
|
||||||
|
{
|
||||||
|
if ( sdhc_mode_sd == 0 )
|
||||||
|
{
|
||||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||||
}
|
}
|
||||||
if (!ret) {
|
if ( !ret )
|
||||||
|
{
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
#define _FATMOUNTER_H_
|
#define _FATMOUNTER_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int fat_sd_mount;
|
extern int fat_sd_mount;
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
#define _GECKO_H_
|
#define _GECKO_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char ascii( char s );
|
char ascii( char s );
|
||||||
|
@ -48,7 +48,8 @@ u8 boothomebrew = 0;
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* roundup Function
|
* roundup Function
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
int roundup(float number) {
|
int roundup( float number )
|
||||||
|
{
|
||||||
if ( number == ( int ) number )
|
if ( number == ( int ) number )
|
||||||
return ( int ) number;
|
return ( int ) number;
|
||||||
else
|
else
|
||||||
@ -58,7 +59,8 @@ int roundup(float number) {
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* MenuHomebrewBrowse
|
* MenuHomebrewBrowse
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
int MenuHomebrewBrowse() {
|
int MenuHomebrewBrowse()
|
||||||
|
{
|
||||||
int menu = MENU_NONE;
|
int menu = MENU_NONE;
|
||||||
int choice = 0;
|
int choice = 0;
|
||||||
|
|
||||||
@ -66,12 +68,14 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
u32 filecount = HomebrewFiles.GetFilecount();
|
u32 filecount = HomebrewFiles.GetFilecount();
|
||||||
|
|
||||||
if (!filecount) {
|
if ( !filecount )
|
||||||
|
{
|
||||||
WindowPrompt( tr( "No .dol or .elf files found." ), 0, tr( "OK" ) );
|
WindowPrompt( tr( "No .dol or .elf files found." ), 0, tr( "OK" ) );
|
||||||
return MENU_DISCLIST;
|
return MENU_DISCLIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
FADE,
|
FADE,
|
||||||
LEFT,
|
LEFT,
|
||||||
RIGHT
|
RIGHT
|
||||||
@ -141,7 +145,8 @@ int MenuHomebrewBrowse() {
|
|||||||
GuiImageData *IconData[4];
|
GuiImageData *IconData[4];
|
||||||
GuiImage *IconImg[4];
|
GuiImage *IconImg[4];
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for ( int i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
IconData[i] = NULL;
|
IconData[i] = NULL;
|
||||||
IconImg[i] = NULL;
|
IconImg[i] = NULL;
|
||||||
}
|
}
|
||||||
@ -150,7 +155,8 @@ int MenuHomebrewBrowse() {
|
|||||||
GuiText backBtnTxt( tr( "Back" ) , 22, THEME.prompttext );
|
GuiText backBtnTxt( tr( "Back" ) , 22, THEME.prompttext );
|
||||||
backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
|
backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
|
||||||
GuiImage backBtnImg( &btnOutline );
|
GuiImage backBtnImg( &btnOutline );
|
||||||
if (Settings.wsprompt == yes) {
|
if ( Settings.wsprompt == yes )
|
||||||
|
{
|
||||||
backBtnTxt.SetWidescreen( CFG.widescreen );
|
backBtnTxt.SetWidescreen( CFG.widescreen );
|
||||||
backBtnImg.SetWidescreen( CFG.widescreen );
|
backBtnImg.SetWidescreen( CFG.widescreen );
|
||||||
}
|
}
|
||||||
@ -297,7 +303,8 @@ int MenuHomebrewBrowse() {
|
|||||||
MainButton4.SetTrigger( &trigA );
|
MainButton4.SetTrigger( &trigA );
|
||||||
|
|
||||||
GuiImage wifiImg( &wifiImgData );
|
GuiImage wifiImg( &wifiImgData );
|
||||||
if (Settings.wsprompt == yes) {
|
if ( Settings.wsprompt == yes )
|
||||||
|
{
|
||||||
wifiImg.SetWidescreen( CFG.widescreen );
|
wifiImg.SetWidescreen( CFG.widescreen );
|
||||||
}
|
}
|
||||||
GuiButton wifiBtn( wifiImg.GetWidth(), wifiImg.GetHeight() );
|
GuiButton wifiBtn( wifiImg.GetWidth(), wifiImg.GetHeight() );
|
||||||
@ -332,7 +339,8 @@ int MenuHomebrewBrowse() {
|
|||||||
const int pages = roundup( filecount / 4.0f );
|
const int pages = roundup( filecount / 4.0f );
|
||||||
bool wifi_btn_loaded = false;
|
bool wifi_btn_loaded = false;
|
||||||
|
|
||||||
while (menu == MENU_NONE) { //set pageToDisplay to 0 to quit
|
while ( menu == MENU_NONE ) //set pageToDisplay to 0 to quit
|
||||||
|
{
|
||||||
VIDEO_WaitVSync ();
|
VIDEO_WaitVSync ();
|
||||||
|
|
||||||
menu = MENU_NONE;
|
menu = MENU_NONE;
|
||||||
@ -345,13 +353,16 @@ int MenuHomebrewBrowse() {
|
|||||||
MainButton3.StopEffect();
|
MainButton3.StopEffect();
|
||||||
MainButton4.StopEffect();
|
MainButton4.StopEffect();
|
||||||
|
|
||||||
if (slidedirection == RIGHT) {
|
if ( slidedirection == RIGHT )
|
||||||
|
{
|
||||||
MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
||||||
MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
||||||
MainButton3.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
MainButton3.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
||||||
MainButton4.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
MainButton4.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60 );
|
||||||
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
||||||
} else if (slidedirection == LEFT) {
|
}
|
||||||
|
else if ( slidedirection == LEFT )
|
||||||
|
{
|
||||||
MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
|
MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
|
||||||
MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
|
MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
|
||||||
MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
|
MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60 );
|
||||||
@ -364,20 +375,25 @@ int MenuHomebrewBrowse() {
|
|||||||
mainWindow->RemoveAll();
|
mainWindow->RemoveAll();
|
||||||
|
|
||||||
/** Set new icons **/
|
/** Set new icons **/
|
||||||
for (int i = 0; i < 4; i++) {
|
for ( int i = 0; i < 4; i++ )
|
||||||
if (IconData[i] != NULL) {
|
{
|
||||||
|
if ( IconData[i] != NULL )
|
||||||
|
{
|
||||||
delete IconData[i];
|
delete IconData[i];
|
||||||
IconData[i] = NULL;
|
IconData[i] = NULL;
|
||||||
}
|
}
|
||||||
if (IconImg[i] != NULL) {
|
if ( IconImg[i] != NULL )
|
||||||
|
{
|
||||||
delete IconImg[i];
|
delete IconImg[i];
|
||||||
IconImg[i] = NULL;
|
IconImg[i] = NULL;
|
||||||
}
|
}
|
||||||
if (fileoffset+i < (int) filecount) {
|
if ( fileoffset + i < ( int ) filecount )
|
||||||
|
{
|
||||||
char iconpath[200];
|
char iconpath[200];
|
||||||
snprintf( iconpath, sizeof( iconpath ), "%sicon.png", HomebrewFiles.GetFilepath( fileoffset + i ) );
|
snprintf( iconpath, sizeof( iconpath ), "%sicon.png", HomebrewFiles.GetFilepath( fileoffset + i ) );
|
||||||
IconData[i] = new GuiImageData( iconpath, 0 );
|
IconData[i] = new GuiImageData( iconpath, 0 );
|
||||||
if (IconData[i]->GetImage()) {
|
if ( IconData[i]->GetImage() )
|
||||||
|
{
|
||||||
IconImg[i] = new GuiImage( IconData[i] );
|
IconImg[i] = new GuiImage( IconData[i] );
|
||||||
IconImg[i]->SetAlignment( ALIGN_LEFT, ALIGN_MIDDLE );
|
IconImg[i]->SetAlignment( ALIGN_LEFT, ALIGN_MIDDLE );
|
||||||
IconImg[i]->SetPosition( 12, 0 );
|
IconImg[i]->SetPosition( 12, 0 );
|
||||||
@ -414,20 +430,25 @@ int MenuHomebrewBrowse() {
|
|||||||
w.Append( &GoRightBtn );
|
w.Append( &GoRightBtn );
|
||||||
w.Append( &GoLeftBtn );
|
w.Append( &GoLeftBtn );
|
||||||
|
|
||||||
if (pageToDisplay == pages) {
|
if ( pageToDisplay == pages )
|
||||||
|
{
|
||||||
int buttonsleft = filecount - ( pages - 1 ) * 4;
|
int buttonsleft = filecount - ( pages - 1 ) * 4;
|
||||||
char * shortpath = NULL;
|
char * shortpath = NULL;
|
||||||
char temp[200];
|
char temp[200];
|
||||||
|
|
||||||
if (buttonsleft > 0) {
|
if ( buttonsleft > 0 )
|
||||||
|
{
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||||
if (XMLInfo[0].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[0].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() );
|
||||||
MainButton1Txt.SetText( MainButtonText );
|
MainButton1Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
|
||||||
MainButton1DescTxt.SetText( MainButtonText );
|
MainButton1DescTxt.SetText( MainButtonText );
|
||||||
MainButton1DescOverTxt.SetText( MainButtonText );
|
MainButton1DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
||||||
@ -439,15 +460,19 @@ int MenuHomebrewBrowse() {
|
|||||||
}
|
}
|
||||||
w.Append( &MainButton1 );
|
w.Append( &MainButton1 );
|
||||||
}
|
}
|
||||||
if (buttonsleft > 1) {
|
if ( buttonsleft > 1 )
|
||||||
|
{
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||||
if (XMLInfo[1].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[1].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() );
|
||||||
MainButton2Txt.SetText( MainButtonText );
|
MainButton2Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
|
||||||
MainButton2DescTxt.SetText( MainButtonText );
|
MainButton2DescTxt.SetText( MainButtonText );
|
||||||
MainButton2DescOverTxt.SetText( MainButtonText );
|
MainButton2DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||||
@ -459,15 +484,19 @@ int MenuHomebrewBrowse() {
|
|||||||
}
|
}
|
||||||
w.Append( &MainButton2 );
|
w.Append( &MainButton2 );
|
||||||
}
|
}
|
||||||
if (buttonsleft > 2) {
|
if ( buttonsleft > 2 )
|
||||||
|
{
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||||
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
||||||
MainButton3Txt.SetText( MainButtonText );
|
MainButton3Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||||
MainButton3DescTxt.SetText( MainButtonText );
|
MainButton3DescTxt.SetText( MainButtonText );
|
||||||
MainButton3DescOverTxt.SetText( MainButtonText );
|
MainButton3DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||||
@ -479,15 +508,19 @@ int MenuHomebrewBrowse() {
|
|||||||
}
|
}
|
||||||
w.Append( &MainButton3 );
|
w.Append( &MainButton3 );
|
||||||
}
|
}
|
||||||
if (buttonsleft > 3) {
|
if ( buttonsleft > 3 )
|
||||||
|
{
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||||
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
||||||
MainButton4Txt.SetText( MainButtonText );
|
MainButton4Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||||
MainButton4DescTxt.SetText( MainButtonText );
|
MainButton4DescTxt.SetText( MainButtonText );
|
||||||
MainButton4DescOverTxt.SetText( MainButtonText );
|
MainButton4DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||||
@ -499,18 +532,23 @@ int MenuHomebrewBrowse() {
|
|||||||
}
|
}
|
||||||
w.Append( &MainButton4 );
|
w.Append( &MainButton4 );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
char temp[200];
|
char temp[200];
|
||||||
char *shortpath = NULL;
|
char *shortpath = NULL;
|
||||||
|
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||||
if (XMLInfo[0].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[0].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetName() );
|
||||||
MainButton1Txt.SetText( MainButtonText );
|
MainButton1Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[0].GetShortDescription() );
|
||||||
MainButton1DescTxt.SetText( MainButtonText );
|
MainButton1DescTxt.SetText( MainButtonText );
|
||||||
MainButton1DescOverTxt.SetText( MainButtonText );
|
MainButton1DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
||||||
@ -524,13 +562,16 @@ int MenuHomebrewBrowse() {
|
|||||||
w.Append( &MainButton1 );
|
w.Append( &MainButton1 );
|
||||||
|
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||||
if (XMLInfo[1].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[1].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetName() );
|
||||||
MainButton2Txt.SetText( MainButtonText );
|
MainButton2Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[1].GetShortDescription() );
|
||||||
MainButton2DescTxt.SetText( MainButtonText );
|
MainButton2DescTxt.SetText( MainButtonText );
|
||||||
MainButton2DescOverTxt.SetText( MainButtonText );
|
MainButton2DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||||
@ -544,13 +585,16 @@ int MenuHomebrewBrowse() {
|
|||||||
w.Append( &MainButton2 );
|
w.Append( &MainButton2 );
|
||||||
|
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||||
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
||||||
MainButton3Txt.SetText( MainButtonText );
|
MainButton3Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||||
MainButton3DescTxt.SetText( MainButtonText );
|
MainButton3DescTxt.SetText( MainButtonText );
|
||||||
MainButton3DescOverTxt.SetText( MainButtonText );
|
MainButton3DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||||
@ -563,13 +607,16 @@ int MenuHomebrewBrowse() {
|
|||||||
w.Append( &MainButton3 );
|
w.Append( &MainButton3 );
|
||||||
|
|
||||||
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
snprintf( temp, sizeof( temp ), "%smeta.xml", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||||
if (XMLInfo[3].LoadHomebrewXMLData(temp) > 0) {
|
if ( XMLInfo[3].LoadHomebrewXMLData( temp ) > 0 )
|
||||||
|
{
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetName() );
|
||||||
MainButton4Txt.SetText( MainButtonText );
|
MainButton4Txt.SetText( MainButtonText );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s", XMLInfo[3].GetShortDescription() );
|
||||||
MainButton4DescTxt.SetText( MainButtonText );
|
MainButton4DescTxt.SetText( MainButtonText );
|
||||||
MainButton4DescOverTxt.SetText( MainButtonText );
|
MainButton4DescOverTxt.SetText( MainButtonText );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||||
shortpath = strrchr( temp, '/' );
|
shortpath = strrchr( temp, '/' );
|
||||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||||
@ -593,17 +640,22 @@ int MenuHomebrewBrowse() {
|
|||||||
MainButton3.SetEffectGrow();
|
MainButton3.SetEffectGrow();
|
||||||
MainButton4.SetEffectGrow();
|
MainButton4.SetEffectGrow();
|
||||||
|
|
||||||
if (slidedirection == FADE) {
|
if ( slidedirection == FADE )
|
||||||
|
{
|
||||||
MainButton1.SetEffect( EFFECT_FADE, 20 );
|
MainButton1.SetEffect( EFFECT_FADE, 20 );
|
||||||
MainButton2.SetEffect( EFFECT_FADE, 20 );
|
MainButton2.SetEffect( EFFECT_FADE, 20 );
|
||||||
MainButton3.SetEffect( EFFECT_FADE, 20 );
|
MainButton3.SetEffect( EFFECT_FADE, 20 );
|
||||||
MainButton4.SetEffect( EFFECT_FADE, 20 );
|
MainButton4.SetEffect( EFFECT_FADE, 20 );
|
||||||
} else if (slidedirection == LEFT) {
|
}
|
||||||
|
else if ( slidedirection == LEFT )
|
||||||
|
{
|
||||||
MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
MainButton1.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
||||||
MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
MainButton2.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
||||||
MainButton3.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
MainButton3.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
||||||
MainButton4.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
MainButton4.SetEffect( EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 60 );
|
||||||
} else if (slidedirection == RIGHT) {
|
}
|
||||||
|
else if ( slidedirection == RIGHT )
|
||||||
|
{
|
||||||
MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
|
MainButton1.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
|
||||||
MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
|
MainButton2.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
|
||||||
MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
|
MainButton3.SetEffect( EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 60 );
|
||||||
@ -616,10 +668,12 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
||||||
|
|
||||||
while (!changed) {
|
while ( !changed )
|
||||||
|
{
|
||||||
VIDEO_WaitVSync ();
|
VIDEO_WaitVSync ();
|
||||||
|
|
||||||
if (MainButton1.GetState() == STATE_CLICKED) {
|
if ( MainButton1.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
char temp[200];
|
char temp[200];
|
||||||
char iconpath[200];
|
char iconpath[200];
|
||||||
char metapath[200];
|
char metapath[200];
|
||||||
@ -639,14 +693,17 @@ int MenuHomebrewBrowse() {
|
|||||||
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
||||||
|
|
||||||
int choice = HBCWindowPrompt( XMLInfo[0].GetName(), XMLInfo[0].GetCoder(), XMLInfo[0].GetVersion(), XMLInfo[0].GetReleasedate(), XMLInfo[0].GetLongDescription(), iconpath, filesize );
|
int choice = HBCWindowPrompt( XMLInfo[0].GetName(), XMLInfo[0].GetCoder(), XMLInfo[0].GetVersion(), XMLInfo[0].GetReleasedate(), XMLInfo[0].GetLongDescription(), iconpath, filesize );
|
||||||
if (choice == 1) {
|
if ( choice == 1 )
|
||||||
|
{
|
||||||
boothomebrew = 1;
|
boothomebrew = 1;
|
||||||
menu = MENU_EXIT;
|
menu = MENU_EXIT;
|
||||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset ), HomebrewFiles.GetFilename( fileoffset ) );
|
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset ), HomebrewFiles.GetFilename( fileoffset ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
MainButton1.ResetState();
|
MainButton1.ResetState();
|
||||||
} else if (MainButton2.GetState() == STATE_CLICKED) {
|
}
|
||||||
|
else if ( MainButton2.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
char temp[200];
|
char temp[200];
|
||||||
char iconpath[200];
|
char iconpath[200];
|
||||||
char metapath[200];
|
char metapath[200];
|
||||||
@ -666,14 +723,17 @@ int MenuHomebrewBrowse() {
|
|||||||
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||||
|
|
||||||
int choice = HBCWindowPrompt( XMLInfo[1].GetName(), XMLInfo[1].GetCoder(), XMLInfo[1].GetVersion(), XMLInfo[1].GetReleasedate(), XMLInfo[1].GetLongDescription(), iconpath, filesize );
|
int choice = HBCWindowPrompt( XMLInfo[1].GetName(), XMLInfo[1].GetCoder(), XMLInfo[1].GetVersion(), XMLInfo[1].GetReleasedate(), XMLInfo[1].GetLongDescription(), iconpath, filesize );
|
||||||
if (choice == 1) {
|
if ( choice == 1 )
|
||||||
|
{
|
||||||
boothomebrew = 1;
|
boothomebrew = 1;
|
||||||
menu = MENU_EXIT;
|
menu = MENU_EXIT;
|
||||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 1 ), HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 1 ), HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
MainButton2.ResetState();
|
MainButton2.ResetState();
|
||||||
} else if (MainButton3.GetState() == STATE_CLICKED) {
|
}
|
||||||
|
else if ( MainButton3.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
char temp[200];
|
char temp[200];
|
||||||
char iconpath[200];
|
char iconpath[200];
|
||||||
char metapath[200];
|
char metapath[200];
|
||||||
@ -693,14 +753,17 @@ int MenuHomebrewBrowse() {
|
|||||||
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||||
|
|
||||||
int choice = HBCWindowPrompt( XMLInfo[2].GetName(), XMLInfo[2].GetCoder(), XMLInfo[2].GetVersion(), XMLInfo[2].GetReleasedate(), XMLInfo[2].GetLongDescription(), iconpath, filesize );
|
int choice = HBCWindowPrompt( XMLInfo[2].GetName(), XMLInfo[2].GetCoder(), XMLInfo[2].GetVersion(), XMLInfo[2].GetReleasedate(), XMLInfo[2].GetLongDescription(), iconpath, filesize );
|
||||||
if (choice == 1) {
|
if ( choice == 1 )
|
||||||
|
{
|
||||||
boothomebrew = 1;
|
boothomebrew = 1;
|
||||||
menu = MENU_EXIT;
|
menu = MENU_EXIT;
|
||||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 2 ), HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 2 ), HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
MainButton3.ResetState();
|
MainButton3.ResetState();
|
||||||
} else if (MainButton4.GetState() == STATE_CLICKED) {
|
}
|
||||||
|
else if ( MainButton4.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
char temp[200];
|
char temp[200];
|
||||||
char iconpath[200];
|
char iconpath[200];
|
||||||
char metapath[200];
|
char metapath[200];
|
||||||
@ -720,7 +783,8 @@ int MenuHomebrewBrowse() {
|
|||||||
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
snprintf( temp, sizeof( temp ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||||
|
|
||||||
int choice = HBCWindowPrompt( XMLInfo[3].GetName(), XMLInfo[3].GetCoder(), XMLInfo[3].GetVersion(), XMLInfo[3].GetReleasedate(), XMLInfo[3].GetLongDescription(), iconpath, filesize );
|
int choice = HBCWindowPrompt( XMLInfo[3].GetName(), XMLInfo[3].GetCoder(), XMLInfo[3].GetVersion(), XMLInfo[3].GetReleasedate(), XMLInfo[3].GetLongDescription(), iconpath, filesize );
|
||||||
if (choice == 1) {
|
if ( choice == 1 )
|
||||||
|
{
|
||||||
boothomebrew = 1;
|
boothomebrew = 1;
|
||||||
menu = MENU_EXIT;
|
menu = MENU_EXIT;
|
||||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 3 ), HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 3 ), HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||||
@ -734,12 +798,14 @@ int MenuHomebrewBrowse() {
|
|||||||
else if ( reset == 1 )
|
else if ( reset == 1 )
|
||||||
Sys_Reboot();
|
Sys_Reboot();
|
||||||
|
|
||||||
else if (backBtn.GetState() == STATE_CLICKED) {
|
else if ( backBtn.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
menu = MENU_DISCLIST;
|
menu = MENU_DISCLIST;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (GoLeftBtn.GetState() == STATE_CLICKED) {
|
else if ( GoLeftBtn.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
pageToDisplay--;
|
pageToDisplay--;
|
||||||
/** Change direction of the flying buttons **/
|
/** Change direction of the flying buttons **/
|
||||||
if ( pageToDisplay < 1 )
|
if ( pageToDisplay < 1 )
|
||||||
@ -749,7 +815,8 @@ int MenuHomebrewBrowse() {
|
|||||||
GoLeftBtn.ResetState();
|
GoLeftBtn.ResetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (GoRightBtn.GetState() == STATE_CLICKED) {
|
else if ( GoRightBtn.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
pageToDisplay++;
|
pageToDisplay++;
|
||||||
/** Change direction of the flying buttons **/
|
/** Change direction of the flying buttons **/
|
||||||
if ( pageToDisplay > pages )
|
if ( pageToDisplay > pages )
|
||||||
@ -759,28 +826,36 @@ int MenuHomebrewBrowse() {
|
|||||||
GoRightBtn.ResetState();
|
GoRightBtn.ResetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (wifiBtn.GetState() == STATE_CLICKED) {
|
else if ( wifiBtn.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
|
|
||||||
ResumeNetworkWait();
|
ResumeNetworkWait();
|
||||||
wifiBtn.ResetState();
|
wifiBtn.ResetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (homo.GetState() == STATE_CLICKED) {
|
else if ( homo.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
cfg_save_global();
|
cfg_save_global();
|
||||||
bgMusic->Pause();
|
bgMusic->Pause();
|
||||||
choice = WindowExitPrompt();
|
choice = WindowExitPrompt();
|
||||||
bgMusic->Resume();
|
bgMusic->Resume();
|
||||||
|
|
||||||
if (choice == 3) {
|
if ( choice == 3 )
|
||||||
|
{
|
||||||
Sys_LoadMenu(); // Back to System Menu
|
Sys_LoadMenu(); // Back to System Menu
|
||||||
} else if (choice == 2) {
|
}
|
||||||
|
else if ( choice == 2 )
|
||||||
|
{
|
||||||
Sys_BackToLoader();
|
Sys_BackToLoader();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
homo.ResetState();
|
homo.ResetState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (infilesize > 0) {
|
else if ( infilesize > 0 )
|
||||||
|
{
|
||||||
char filesizetxt[50];
|
char filesizetxt[50];
|
||||||
char temp[50];
|
char temp[50];
|
||||||
|
|
||||||
@ -793,14 +868,18 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
int choice = WindowPrompt( filesizetxt, temp, tr( "OK" ), tr( "Cancel" ) );
|
int choice = WindowPrompt( filesizetxt, temp, tr( "OK" ), tr( "Cancel" ) );
|
||||||
|
|
||||||
if (choice == 1) {
|
if ( choice == 1 )
|
||||||
|
{
|
||||||
|
|
||||||
int res = AllocHomebrewMemory( infilesize );
|
int res = AllocHomebrewMemory( infilesize );
|
||||||
|
|
||||||
if (res < 0) {
|
if ( res < 0 )
|
||||||
|
{
|
||||||
CloseConnection();
|
CloseConnection();
|
||||||
WindowPrompt( tr( "Not enough free memory." ), 0, tr( "OK" ) );
|
WindowPrompt( tr( "Not enough free memory." ), 0, tr( "OK" ) );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
u32 read = 0;
|
u32 read = 0;
|
||||||
u8 *temp = NULL;
|
u8 *temp = NULL;
|
||||||
int len = NETWORKBLOCKSIZE;
|
int len = NETWORKBLOCKSIZE;
|
||||||
@ -808,7 +887,8 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
u8 *ptr = temp;
|
u8 *ptr = temp;
|
||||||
while (read < infilesize) {
|
while ( read < infilesize )
|
||||||
|
{
|
||||||
|
|
||||||
ShowProgress( tr( "Receiving file from:" ), GetIncommingIP(), NULL, read, infilesize, true );
|
ShowProgress( tr( "Receiving file from:" ), GetIncommingIP(), NULL, read, infilesize, true );
|
||||||
|
|
||||||
@ -819,12 +899,14 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
int result = network_read( ptr, len );
|
int result = network_read( ptr, len );
|
||||||
|
|
||||||
if (result < 0) {
|
if ( result < 0 )
|
||||||
|
{
|
||||||
WindowPrompt( tr( "Error while transfering data." ), 0, tr( "OK" ) );
|
WindowPrompt( tr( "Error while transfering data." ), 0, tr( "OK" ) );
|
||||||
error = true;
|
error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!result) {
|
if ( !result )
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,15 +916,18 @@ int MenuHomebrewBrowse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char filename[101];
|
char filename[101];
|
||||||
if (!error) {
|
if ( !error )
|
||||||
|
{
|
||||||
|
|
||||||
network_read( ( u8* ) &filename, 100 );
|
network_read( ( u8* ) &filename, 100 );
|
||||||
|
|
||||||
// Do we need to unzip this thing?
|
// Do we need to unzip this thing?
|
||||||
if (wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4) {
|
if ( wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4 )
|
||||||
|
{
|
||||||
|
|
||||||
// We need to unzip...
|
// We need to unzip...
|
||||||
if (temp[0] == 'P' && temp[1] == 'K' && temp[2] == 0x03 && temp[3] == 0x04) {
|
if ( temp[0] == 'P' && temp[1] == 'K' && temp[2] == 0x03 && temp[3] == 0x04 )
|
||||||
|
{
|
||||||
// It's a zip file, unzip to the apps directory
|
// It's a zip file, unzip to the apps directory
|
||||||
|
|
||||||
// Zip archive, ask for permission to install the zip
|
// Zip archive, ask for permission to install the zip
|
||||||
@ -857,9 +942,12 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
// Now unzip the zip file...
|
// Now unzip the zip file...
|
||||||
unzFile uf = unzOpen( zippath );
|
unzFile uf = unzOpen( zippath );
|
||||||
if (uf==NULL) {
|
if ( uf == NULL )
|
||||||
|
{
|
||||||
error = true;
|
error = true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
extractZip( uf, 0, 1, 0, Settings.homebrewapps_path );
|
extractZip( uf, 0, 1, 0, Settings.homebrewapps_path );
|
||||||
unzCloseCurrentFile( uf );
|
unzCloseCurrentFile( uf );
|
||||||
|
|
||||||
@ -869,10 +957,14 @@ int MenuHomebrewBrowse() {
|
|||||||
menu = MENU_HOMEBREWBROWSE;
|
menu = MENU_HOMEBREWBROWSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
} else if (uncfilesize != 0) { // if uncfilesize == 0, it's not compressed
|
}
|
||||||
|
else if ( uncfilesize != 0 ) // if uncfilesize == 0, it's not compressed
|
||||||
|
{
|
||||||
// It's compressed, uncompress
|
// It's compressed, uncompress
|
||||||
u8 *unc = ( u8 * ) malloc( uncfilesize );
|
u8 *unc = ( u8 * ) malloc( uncfilesize );
|
||||||
uLongf f = uncfilesize;
|
uLongf f = uncfilesize;
|
||||||
@ -885,7 +977,8 @@ int MenuHomebrewBrowse() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error && strstr(filename,".zip") == NULL) {
|
if ( !error && strstr( filename, ".zip" ) == NULL )
|
||||||
|
{
|
||||||
innetbuffer = temp;
|
innetbuffer = temp;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -893,21 +986,29 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
ProgressStop();
|
ProgressStop();
|
||||||
|
|
||||||
if (error || read != infilesize) {
|
if ( error || read != infilesize )
|
||||||
|
{
|
||||||
WindowPrompt( tr( "Error:" ), tr( "No data could be read." ), tr( "OK" ) );
|
WindowPrompt( tr( "Error:" ), tr( "No data could be read." ), tr( "OK" ) );
|
||||||
FreeHomebrewBuffer();
|
FreeHomebrewBuffer();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( strstr( filename, ".dol" ) || strstr( filename, ".DOL" )
|
if ( strstr( filename, ".dol" ) || strstr( filename, ".DOL" )
|
||||||
|| strstr(filename,".elf") || strstr(filename,".ELF")) {
|
|| strstr( filename, ".elf" ) || strstr( filename, ".ELF" ) )
|
||||||
|
{
|
||||||
boothomebrew = 2;
|
boothomebrew = 2;
|
||||||
AddBootArgument( filename );
|
AddBootArgument( filename );
|
||||||
menu = MENU_EXIT;
|
menu = MENU_EXIT;
|
||||||
CloseConnection();
|
CloseConnection();
|
||||||
break;
|
break;
|
||||||
} else if (strstr(filename,".zip")) {
|
}
|
||||||
|
else if ( strstr( filename, ".zip" ) )
|
||||||
|
{
|
||||||
WindowPrompt( tr( "Success:" ), tr( "Uploaded ZIP file installed to homebrew directory." ), tr( "OK" ) );
|
WindowPrompt( tr( "Success:" ), tr( "Uploaded ZIP file installed to homebrew directory." ), tr( "OK" ) );
|
||||||
CloseConnection();
|
CloseConnection();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
FreeHomebrewBuffer();
|
FreeHomebrewBuffer();
|
||||||
WindowPrompt( tr( "ERROR:" ), tr( "Not a DOL/ELF file." ), tr( "OK" ) );
|
WindowPrompt( tr( "ERROR:" ), tr( "Not a DOL/ELF file." ), tr( "OK" ) );
|
||||||
}
|
}
|
||||||
@ -918,7 +1019,8 @@ int MenuHomebrewBrowse() {
|
|||||||
ResumeNetworkWait();
|
ResumeNetworkWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (channelBtn.GetState() == STATE_CLICKED) {
|
else if ( channelBtn.GetState() == STATE_CLICKED )
|
||||||
|
{
|
||||||
w.SetState( STATE_DISABLED );
|
w.SetState( STATE_DISABLED );
|
||||||
//10001 are the channels that are installed as channels, not including shop channel/mii channel etc
|
//10001 are the channels that are installed as channels, not including shop channel/mii channel etc
|
||||||
TitleBrowser();
|
TitleBrowser();
|
||||||
@ -929,8 +1031,10 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsNetworkInit()) {
|
if ( IsNetworkInit() )
|
||||||
if (!wifi_btn_loaded) {
|
{
|
||||||
|
if ( !wifi_btn_loaded )
|
||||||
|
{
|
||||||
wifiBtn.SetAlpha( 255 );
|
wifiBtn.SetAlpha( 255 );
|
||||||
|
|
||||||
titleTT = new GuiTooltip( GetNetworkIP() );
|
titleTT = new GuiTooltip( GetNetworkIP() );
|
||||||
@ -947,12 +1051,15 @@ int MenuHomebrewBrowse() {
|
|||||||
|
|
||||||
HaltGui();
|
HaltGui();
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for ( int i = 0; i < 4; i++ )
|
||||||
if (IconData[i] != NULL) {
|
{
|
||||||
|
if ( IconData[i] != NULL )
|
||||||
|
{
|
||||||
delete IconData[i];
|
delete IconData[i];
|
||||||
IconData[i] = NULL;
|
IconData[i] = NULL;
|
||||||
}
|
}
|
||||||
if (IconImg[i] != NULL) {
|
if ( IconImg[i] != NULL )
|
||||||
|
{
|
||||||
delete IconImg[i];
|
delete IconImg[i];
|
||||||
IconImg[i] = NULL;
|
IconImg[i] = NULL;
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,13 @@
|
|||||||
|
|
||||||
#include "HomebrewFiles.h"
|
#include "HomebrewFiles.h"
|
||||||
|
|
||||||
HomebrewFiles::HomebrewFiles(const char * path) {
|
HomebrewFiles::HomebrewFiles( const char * path )
|
||||||
|
{
|
||||||
filecount = 0;
|
filecount = 0;
|
||||||
|
|
||||||
FileInfo = ( FileInfos * ) malloc( sizeof( FileInfos ) );
|
FileInfo = ( FileInfos * ) malloc( sizeof( FileInfos ) );
|
||||||
if (!FileInfo) {
|
if ( !FileInfo )
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,42 +25,54 @@ HomebrewFiles::HomebrewFiles(const char * path) {
|
|||||||
this->SortList();
|
this->SortList();
|
||||||
}
|
}
|
||||||
|
|
||||||
HomebrewFiles::~HomebrewFiles() {
|
HomebrewFiles::~HomebrewFiles()
|
||||||
if (FileInfo) {
|
{
|
||||||
|
if ( FileInfo )
|
||||||
|
{
|
||||||
free( FileInfo );
|
free( FileInfo );
|
||||||
FileInfo = NULL;
|
FileInfo = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HomebrewFiles::LoadPath(const char * folderpath) {
|
bool HomebrewFiles::LoadPath( const char * folderpath )
|
||||||
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
DIR_ITER *dir = NULL;
|
DIR_ITER *dir = NULL;
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
|
|
||||||
dir = diropen( folderpath );
|
dir = diropen( folderpath );
|
||||||
if (dir == NULL) {
|
if ( dir == NULL )
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dirnext(dir,filename,&st) == 0) {
|
while ( dirnext( dir, filename, &st ) == 0 )
|
||||||
if ((st.st_mode & S_IFDIR) != 0) {
|
{
|
||||||
if (strcmp(filename,".") != 0 && strcmp(filename,"..") != 0) {
|
if ( ( st.st_mode & S_IFDIR ) != 0 )
|
||||||
|
{
|
||||||
|
if ( strcmp( filename, "." ) != 0 && strcmp( filename, ".." ) != 0 )
|
||||||
|
{
|
||||||
char currentname[200];
|
char currentname[200];
|
||||||
snprintf( currentname, sizeof( currentname ), "%s%s/", folderpath, filename );
|
snprintf( currentname, sizeof( currentname ), "%s%s/", folderpath, filename );
|
||||||
this->LoadPath( currentname );
|
this->LoadPath( currentname );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
char temp[5];
|
char temp[5];
|
||||||
for (int i = 0; i < 5; i++) {
|
for ( int i = 0; i < 5; i++ )
|
||||||
|
{
|
||||||
temp[i] = filename[strlen( filename )-4+i];
|
temp[i] = filename[strlen( filename )-4+i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 )
|
if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 )
|
||||||
&& filecount < MAXHOMEBREWS && filename[0]!='.') {
|
&& filecount < MAXHOMEBREWS && filename[0] != '.' )
|
||||||
|
{
|
||||||
|
|
||||||
FileInfo = ( FileInfos * ) realloc( FileInfo, ( filecount + 1 ) * sizeof( FileInfos ) );
|
FileInfo = ( FileInfos * ) realloc( FileInfo, ( filecount + 1 ) * sizeof( FileInfos ) );
|
||||||
|
|
||||||
if (!FileInfo) {
|
if ( !FileInfo )
|
||||||
|
{
|
||||||
free( FileInfo );
|
free( FileInfo );
|
||||||
FileInfo = NULL;
|
FileInfo = NULL;
|
||||||
filecount = 0;
|
filecount = 0;
|
||||||
@ -80,37 +94,43 @@ bool HomebrewFiles::LoadPath(const char * folderpath) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * HomebrewFiles::GetFilename(int ind) {
|
char * HomebrewFiles::GetFilename( int ind )
|
||||||
|
{
|
||||||
if ( ind > filecount )
|
if ( ind > filecount )
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
return FileInfo[ind].FileName;
|
return FileInfo[ind].FileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * HomebrewFiles::GetFilepath(int ind) {
|
char * HomebrewFiles::GetFilepath( int ind )
|
||||||
|
{
|
||||||
if ( ind > filecount )
|
if ( ind > filecount )
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
return FileInfo[ind].FilePath;
|
return FileInfo[ind].FilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int HomebrewFiles::GetFilesize(int ind) {
|
unsigned int HomebrewFiles::GetFilesize( int ind )
|
||||||
|
{
|
||||||
if ( ind > filecount || !filecount || !FileInfo )
|
if ( ind > filecount || !filecount || !FileInfo )
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
return FileInfo[ind].FileSize;
|
return FileInfo[ind].FileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int HomebrewFiles::GetFilecount() {
|
int HomebrewFiles::GetFilecount()
|
||||||
|
{
|
||||||
return filecount;
|
return filecount;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ListCompare(const void *a, const void *b) {
|
static int ListCompare( const void *a, const void *b )
|
||||||
|
{
|
||||||
FileInfos *ab = ( FileInfos* ) a;
|
FileInfos *ab = ( FileInfos* ) a;
|
||||||
FileInfos *bb = ( FileInfos* ) b;
|
FileInfos *bb = ( FileInfos* ) b;
|
||||||
|
|
||||||
return stricmp( ( char * ) ab->FilePath, ( char * ) bb->FilePath );
|
return stricmp( ( char * ) ab->FilePath, ( char * ) bb->FilePath );
|
||||||
}
|
}
|
||||||
void HomebrewFiles::SortList() {
|
void HomebrewFiles::SortList()
|
||||||
|
{
|
||||||
qsort( FileInfo, filecount, sizeof( FileInfos ), ListCompare );
|
qsort( FileInfo, filecount, sizeof( FileInfos ), ListCompare );
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,15 @@
|
|||||||
|
|
||||||
#define MAXHOMEBREWS 500
|
#define MAXHOMEBREWS 500
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char FileName[100];
|
char FileName[100];
|
||||||
char FilePath[150];
|
char FilePath[150];
|
||||||
unsigned int FileSize;
|
unsigned int FileSize;
|
||||||
} FileInfos;
|
} FileInfos;
|
||||||
|
|
||||||
class HomebrewFiles {
|
class HomebrewFiles
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
//!Constructor
|
//!Constructor
|
||||||
//!\param path Path where to check for homebrew files
|
//!\param path Path where to check for homebrew files
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
#include "dolloader.h"
|
#include "dolloader.h"
|
||||||
|
|
||||||
typedef struct _dolheader {
|
typedef struct _dolheader
|
||||||
|
{
|
||||||
u32 text_pos[7];
|
u32 text_pos[7];
|
||||||
u32 data_pos[11];
|
u32 data_pos[11];
|
||||||
u32 text_start[7];
|
u32 text_start[7];
|
||||||
@ -20,19 +21,23 @@ typedef struct _dolheader {
|
|||||||
u32 entry_point;
|
u32 entry_point;
|
||||||
} dolheader;
|
} dolheader;
|
||||||
|
|
||||||
u32 load_dol(const void *dolstart, struct __argv *argv) {
|
u32 load_dol( const void *dolstart, struct __argv *argv )
|
||||||
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
dolheader *dolfile;
|
dolheader *dolfile;
|
||||||
|
|
||||||
if (dolstart) {
|
if ( dolstart )
|
||||||
|
{
|
||||||
dolfile = ( dolheader * ) dolstart;
|
dolfile = ( dolheader * ) dolstart;
|
||||||
for (i = 0; i < 7; i++) {
|
for ( i = 0; i < 7; i++ )
|
||||||
|
{
|
||||||
if ( ( !dolfile->text_size[i] ) || ( dolfile->text_start[i] < 0x100 ) ) continue;
|
if ( ( !dolfile->text_size[i] ) || ( dolfile->text_start[i] < 0x100 ) ) continue;
|
||||||
ICInvalidateRange ( ( void * ) dolfile->text_start[i], dolfile->text_size[i] );
|
ICInvalidateRange ( ( void * ) dolfile->text_start[i], dolfile->text_size[i] );
|
||||||
memcpy( ( void * ) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i] );
|
memcpy( ( void * ) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 11; i++) {
|
for ( i = 0; i < 11; i++ )
|
||||||
|
{
|
||||||
if ( ( !dolfile->data_size[i] ) || ( dolfile->data_start[i] < 0x100 ) ) continue;
|
if ( ( !dolfile->data_size[i] ) || ( dolfile->data_start[i] < 0x100 ) ) continue;
|
||||||
memcpy( ( void * ) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i] );
|
memcpy( ( void * ) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i] );
|
||||||
DCFlushRangeNoSync ( ( void * ) dolfile->data_start[i], dolfile->data_size[i] );
|
DCFlushRangeNoSync ( ( void * ) dolfile->data_start[i], dolfile->data_size[i] );
|
||||||
@ -41,7 +46,8 @@ u32 load_dol(const void *dolstart, struct __argv *argv) {
|
|||||||
memset ( ( void * ) dolfile->bss_start, 0, dolfile->bss_size );
|
memset ( ( void * ) dolfile->bss_start, 0, dolfile->bss_size );
|
||||||
DCFlushRange( ( void * ) dolfile->bss_start, dolfile->bss_size );
|
DCFlushRange( ( void * ) dolfile->bss_start, dolfile->bss_size );
|
||||||
|
|
||||||
if (argv && argv->argvMagic == ARGV_MAGIC) {
|
if ( argv && argv->argvMagic == ARGV_MAGIC )
|
||||||
|
{
|
||||||
void *new_argv = ( void * )( dolfile->entry_point + 8 );
|
void *new_argv = ( void * )( dolfile->entry_point + 8 );
|
||||||
memcpy( new_argv, argv, sizeof( *argv ) );
|
memcpy( new_argv, argv, sizeof( *argv ) );
|
||||||
DCFlushRange( new_argv, sizeof( *argv ) );
|
DCFlushRange( new_argv, sizeof( *argv ) );
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
#define _DOLLOADER_H_
|
#define _DOLLOADER_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void __exception_closeall();
|
extern void __exception_closeall();
|
||||||
|
@ -77,8 +77,10 @@ void SetupPads()
|
|||||||
* ShutoffRumble
|
* ShutoffRumble
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
void ShutoffRumble() {
|
void ShutoffRumble()
|
||||||
for (int i=0;i<4;i++) {
|
{
|
||||||
|
for ( int i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
WPAD_Rumble( i, 0 );
|
WPAD_Rumble( i, 0 );
|
||||||
rumbleCount[i] = 0;
|
rumbleCount[i] = 0;
|
||||||
}
|
}
|
||||||
@ -88,14 +90,20 @@ void ShutoffRumble() {
|
|||||||
* DoRumble
|
* DoRumble
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
void DoRumble(int i) {
|
void DoRumble( int i )
|
||||||
if (rumbleRequest[i] && rumbleCount[i] < 3) {
|
{
|
||||||
|
if ( rumbleRequest[i] && rumbleCount[i] < 3 )
|
||||||
|
{
|
||||||
WPAD_Rumble( i, 1 ); // rumble on
|
WPAD_Rumble( i, 1 ); // rumble on
|
||||||
rumbleCount[i]++;
|
rumbleCount[i]++;
|
||||||
} else if (rumbleRequest[i]) {
|
}
|
||||||
|
else if ( rumbleRequest[i] )
|
||||||
|
{
|
||||||
rumbleCount[i] = 20;
|
rumbleCount[i] = 20;
|
||||||
rumbleRequest[i] = 0;
|
rumbleRequest[i] = 0;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( rumbleCount[i] )
|
if ( rumbleCount[i] )
|
||||||
rumbleCount[i]--;
|
rumbleCount[i]--;
|
||||||
WPAD_Rumble( i, 0 ); // rumble off
|
WPAD_Rumble( i, 0 ); // rumble off
|
||||||
@ -108,25 +116,31 @@ void DoRumble(int i) {
|
|||||||
* Get X/Y value from Wii Joystick (classic, nunchuk) input
|
* Get X/Y value from Wii Joystick (classic, nunchuk) input
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
s8 WPAD_Stick(u8 chan, u8 right, int axis) {
|
s8 WPAD_Stick( u8 chan, u8 right, int axis )
|
||||||
|
{
|
||||||
float mag = 0.0;
|
float mag = 0.0;
|
||||||
float ang = 0.0;
|
float ang = 0.0;
|
||||||
WPADData *data = WPAD_Data( chan );
|
WPADData *data = WPAD_Data( chan );
|
||||||
|
|
||||||
switch (data->exp.type) {
|
switch ( data->exp.type )
|
||||||
|
{
|
||||||
case WPAD_EXP_NUNCHUK:
|
case WPAD_EXP_NUNCHUK:
|
||||||
case WPAD_EXP_GUITARHERO3:
|
case WPAD_EXP_GUITARHERO3:
|
||||||
if (right == 0) {
|
if ( right == 0 )
|
||||||
|
{
|
||||||
mag = data->exp.nunchuk.js.mag;
|
mag = data->exp.nunchuk.js.mag;
|
||||||
ang = data->exp.nunchuk.js.ang;
|
ang = data->exp.nunchuk.js.ang;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WPAD_EXP_CLASSIC:
|
case WPAD_EXP_CLASSIC:
|
||||||
if (right == 0) {
|
if ( right == 0 )
|
||||||
|
{
|
||||||
mag = data->exp.classic.ljs.mag;
|
mag = data->exp.classic.ljs.mag;
|
||||||
ang = data->exp.classic.ljs.ang;
|
ang = data->exp.classic.ljs.ang;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
mag = data->exp.classic.rjs.mag;
|
mag = data->exp.classic.rjs.mag;
|
||||||
ang = data->exp.classic.rjs.ang;
|
ang = data->exp.classic.rjs.ang;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
#include "network/networkops.h"
|
#include "network/networkops.h"
|
||||||
#include "network/http.h"
|
#include "network/http.h"
|
||||||
|
|
||||||
int updateLanguageFiles() {
|
int updateLanguageFiles()
|
||||||
|
{
|
||||||
char languageFiles[50][MAXLANGUAGEFILES];
|
char languageFiles[50][MAXLANGUAGEFILES];
|
||||||
|
|
||||||
//get all the files in the language path
|
//get all the files in the language path
|
||||||
@ -23,10 +24,12 @@ int updateLanguageFiles() {
|
|||||||
if ( !countfiles ) return -2;
|
if ( !countfiles ) return -2;
|
||||||
|
|
||||||
//now from the files we got, get only the .lang files
|
//now from the files we got, get only the .lang files
|
||||||
for (int cnt = 0; cnt < countfiles; cnt++) {
|
for ( int cnt = 0; cnt < countfiles; cnt++ )
|
||||||
|
{
|
||||||
char filename[64];
|
char filename[64];
|
||||||
strlcpy( filename, GetFileName( cnt ), sizeof( filename ) );
|
strlcpy( filename, GetFileName( cnt ), sizeof( filename ) );
|
||||||
if (strcasestr(filename,".lang")) {
|
if ( strcasestr( filename, ".lang" ) )
|
||||||
|
{
|
||||||
strcpy( languageFiles[cnt], filename );
|
strcpy( languageFiles[cnt], filename );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,9 +39,11 @@ int updateLanguageFiles() {
|
|||||||
//we assume that the network will already be init by another function
|
//we assume that the network will already be init by another function
|
||||||
// ( that has gui eletents in it because this one doesn't)
|
// ( that has gui eletents in it because this one doesn't)
|
||||||
int done = 0, j = 0;
|
int done = 0, j = 0;
|
||||||
if (IsNetworkInit()) {
|
if ( IsNetworkInit() )
|
||||||
|
{
|
||||||
//build the URL, save path, and download each file and save it
|
//build the URL, save path, and download each file and save it
|
||||||
while (j<countfiles) {
|
while ( j < countfiles )
|
||||||
|
{
|
||||||
char savepath[150];
|
char savepath[150];
|
||||||
char codeurl[200];
|
char codeurl[200];
|
||||||
snprintf( codeurl, sizeof( codeurl ), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s", languageFiles[j] );
|
snprintf( codeurl, sizeof( codeurl ), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s", languageFiles[j] );
|
||||||
@ -46,10 +51,12 @@ int updateLanguageFiles() {
|
|||||||
|
|
||||||
struct block file = downloadfile( codeurl );
|
struct block file = downloadfile( codeurl );
|
||||||
|
|
||||||
if (file.data != NULL) {
|
if ( file.data != NULL )
|
||||||
|
{
|
||||||
FILE * pfile;
|
FILE * pfile;
|
||||||
pfile = fopen( savepath, "wb" );
|
pfile = fopen( savepath, "wb" );
|
||||||
if(pfile != NULL) {
|
if ( pfile != NULL )
|
||||||
|
{
|
||||||
fwrite( file.data, 1, file.size, pfile );
|
fwrite( file.data, 1, file.size, pfile );
|
||||||
fclose( pfile );
|
fclose( pfile );
|
||||||
free( file.data );
|
free( file.data );
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
#include <gctypes.h>
|
#include <gctypes.h>
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
|
||||||
typedef struct _MSG {
|
typedef struct _MSG
|
||||||
|
{
|
||||||
u32 id;
|
u32 id;
|
||||||
char* msgstr;
|
char* msgstr;
|
||||||
struct _MSG *next;
|
struct _MSG *next;
|
||||||
@ -18,17 +19,20 @@ static MSG *baseMSG=0;
|
|||||||
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
||||||
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
||||||
static inline u32
|
static inline u32
|
||||||
hash_string (const char *str_param) {
|
hash_string ( const char *str_param )
|
||||||
|
{
|
||||||
u32 hval, g;
|
u32 hval, g;
|
||||||
const char *str = str_param;
|
const char *str = str_param;
|
||||||
|
|
||||||
/* Compute the hash value for the given string. */
|
/* Compute the hash value for the given string. */
|
||||||
hval = 0;
|
hval = 0;
|
||||||
while (*str != '\0') {
|
while ( *str != '\0' )
|
||||||
|
{
|
||||||
hval <<= 4;
|
hval <<= 4;
|
||||||
hval += ( u8 ) * str++;
|
hval += ( u8 ) * str++;
|
||||||
g = hval & ( ( u32 ) 0xf << ( HASHWORDBITS - 4 ) );
|
g = hval & ( ( u32 ) 0xf << ( HASHWORDBITS - 4 ) );
|
||||||
if (g != 0) {
|
if ( g != 0 )
|
||||||
|
{
|
||||||
hval ^= g >> ( HASHWORDBITS - 8 );
|
hval ^= g >> ( HASHWORDBITS - 8 );
|
||||||
hval ^= g;
|
hval ^= g;
|
||||||
}
|
}
|
||||||
@ -38,7 +42,8 @@ hash_string (const char *str_param) {
|
|||||||
|
|
||||||
/* Expand some escape sequences found in the argument string. */
|
/* Expand some escape sequences found in the argument string. */
|
||||||
static char *
|
static char *
|
||||||
expand_escape (const char *str) {
|
expand_escape ( const char *str )
|
||||||
|
{
|
||||||
char *retval, *rp;
|
char *retval, *rp;
|
||||||
const char *cp = str;
|
const char *cp = str;
|
||||||
|
|
||||||
@ -50,10 +55,12 @@ expand_escape (const char *str) {
|
|||||||
*rp++ = *cp++;
|
*rp++ = *cp++;
|
||||||
if ( cp[0] == '\0' )
|
if ( cp[0] == '\0' )
|
||||||
goto terminate;
|
goto terminate;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
|
|
||||||
/* Here cp[0] == '\\'. */
|
/* Here cp[0] == '\\'. */
|
||||||
switch (*++cp) {
|
switch ( *++cp )
|
||||||
|
{
|
||||||
case '\"': /* " */
|
case '\"': /* " */
|
||||||
*rp++ = '\"';
|
*rp++ = '\"';
|
||||||
++cp;
|
++cp;
|
||||||
@ -97,14 +104,17 @@ expand_escape (const char *str) {
|
|||||||
case '4':
|
case '4':
|
||||||
case '5':
|
case '5':
|
||||||
case '6':
|
case '6':
|
||||||
case '7': {
|
case '7':
|
||||||
|
{
|
||||||
int ch = *cp++ - '0';
|
int ch = *cp++ - '0';
|
||||||
|
|
||||||
if (*cp >= '0' && *cp <= '7') {
|
if ( *cp >= '0' && *cp <= '7' )
|
||||||
|
{
|
||||||
ch *= 8;
|
ch *= 8;
|
||||||
ch += *cp++ - '0';
|
ch += *cp++ - '0';
|
||||||
|
|
||||||
if (*cp >= '0' && *cp <= '7') {
|
if ( *cp >= '0' && *cp <= '7' )
|
||||||
|
{
|
||||||
ch *= 8;
|
ch *= 8;
|
||||||
ch += *cp++ - '0';
|
ch += *cp++ - '0';
|
||||||
}
|
}
|
||||||
@ -119,7 +129,8 @@ expand_escape (const char *str) {
|
|||||||
|
|
||||||
while ( cp[0] != '\0' && cp[0] != '\\' )
|
while ( cp[0] != '\0' && cp[0] != '\\' )
|
||||||
*rp++ = *cp++;
|
*rp++ = *cp++;
|
||||||
} while (cp[0] != '\0');
|
}
|
||||||
|
while ( cp[0] != '\0' );
|
||||||
|
|
||||||
/* Terminate string. */
|
/* Terminate string. */
|
||||||
terminate:
|
terminate:
|
||||||
@ -127,27 +138,33 @@ terminate:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MSG *findMSG(u32 id) {
|
static MSG *findMSG( u32 id )
|
||||||
|
{
|
||||||
MSG *msg;
|
MSG *msg;
|
||||||
for (msg=baseMSG; msg; msg=msg->next) {
|
for ( msg = baseMSG; msg; msg = msg->next )
|
||||||
|
{
|
||||||
if ( msg->id == id )
|
if ( msg->id == id )
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MSG *setMSG(const char *msgid, const char *msgstr) {
|
static MSG *setMSG( const char *msgid, const char *msgstr )
|
||||||
|
{
|
||||||
u32 id = hash_string( msgid );
|
u32 id = hash_string( msgid );
|
||||||
MSG *msg = findMSG( id );
|
MSG *msg = findMSG( id );
|
||||||
if (!msg) {
|
if ( !msg )
|
||||||
|
{
|
||||||
msg = ( MSG * )malloc( sizeof( MSG ) );
|
msg = ( MSG * )malloc( sizeof( MSG ) );
|
||||||
msg->id = id;
|
msg->id = id;
|
||||||
msg->msgstr = NULL;
|
msg->msgstr = NULL;
|
||||||
msg->next = baseMSG;
|
msg->next = baseMSG;
|
||||||
baseMSG = msg;
|
baseMSG = msg;
|
||||||
}
|
}
|
||||||
if (msg) {
|
if ( msg )
|
||||||
if (msgstr) {
|
{
|
||||||
|
if ( msgstr )
|
||||||
|
{
|
||||||
if ( msg->msgstr ) free( msg->msgstr );
|
if ( msg->msgstr ) free( msg->msgstr );
|
||||||
//msg->msgstr = strdup(msgstr);
|
//msg->msgstr = strdup(msgstr);
|
||||||
msg->msgstr = expand_escape( msgstr );
|
msg->msgstr = expand_escape( msgstr );
|
||||||
@ -156,8 +173,10 @@ static MSG *setMSG(const char *msgid, const char *msgstr) {
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void gettextCleanUp(void) {
|
void gettextCleanUp( void )
|
||||||
while (baseMSG) {
|
{
|
||||||
|
while ( baseMSG )
|
||||||
|
{
|
||||||
MSG *nextMsg = baseMSG->next;
|
MSG *nextMsg = baseMSG->next;
|
||||||
free( baseMSG->msgstr );
|
free( baseMSG->msgstr );
|
||||||
free( baseMSG );
|
free( baseMSG );
|
||||||
@ -166,7 +185,8 @@ void gettextCleanUp(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool gettextLoadLanguage(const char* langFile) {
|
bool gettextLoadLanguage( const char* langFile )
|
||||||
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char line[200];
|
char line[200];
|
||||||
char *lastID = NULL;
|
char *lastID = NULL;
|
||||||
@ -176,23 +196,29 @@ bool gettextLoadLanguage(const char* langFile) {
|
|||||||
if ( !f )
|
if ( !f )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), f)) {
|
while ( fgets( line, sizeof( line ), f ) )
|
||||||
|
{
|
||||||
// lines starting with # are comments
|
// lines starting with # are comments
|
||||||
if ( line[0] == '#' )
|
if ( line[0] == '#' )
|
||||||
continue;
|
continue;
|
||||||
else if (strncmp(line, "msgid \"", 7) == 0) {
|
else if ( strncmp( line, "msgid \"", 7 ) == 0 )
|
||||||
|
{
|
||||||
char *msgid, *end;
|
char *msgid, *end;
|
||||||
if (lastID) {
|
if ( lastID )
|
||||||
|
{
|
||||||
free( lastID );
|
free( lastID );
|
||||||
lastID = NULL;
|
lastID = NULL;
|
||||||
}
|
}
|
||||||
msgid = &line[7];
|
msgid = &line[7];
|
||||||
end = strrchr( msgid, '"' );
|
end = strrchr( msgid, '"' );
|
||||||
if (end && end-msgid>1) {
|
if ( end && end - msgid > 1 )
|
||||||
|
{
|
||||||
*end = 0;
|
*end = 0;
|
||||||
lastID = strdup( msgid );
|
lastID = strdup( msgid );
|
||||||
}
|
}
|
||||||
} else if (strncmp(line, "msgstr \"", 8) == 0) {
|
}
|
||||||
|
else if ( strncmp( line, "msgstr \"", 8 ) == 0 )
|
||||||
|
{
|
||||||
char *msgstr, *end;
|
char *msgstr, *end;
|
||||||
|
|
||||||
if ( lastID == NULL )
|
if ( lastID == NULL )
|
||||||
@ -200,7 +226,8 @@ bool gettextLoadLanguage(const char* langFile) {
|
|||||||
|
|
||||||
msgstr = &line[8];
|
msgstr = &line[8];
|
||||||
end = strrchr( msgstr, '"' );
|
end = strrchr( msgstr, '"' );
|
||||||
if (end && end-msgstr>1) {
|
if ( end && end - msgstr > 1 )
|
||||||
|
{
|
||||||
*end = 0;
|
*end = 0;
|
||||||
setMSG( lastID, msgstr );
|
setMSG( lastID, msgstr );
|
||||||
}
|
}
|
||||||
@ -213,7 +240,8 @@ bool gettextLoadLanguage(const char* langFile) {
|
|||||||
fclose( f );
|
fclose( f );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const char *gettext(const char *msgid) {
|
const char *gettext( const char *msgid )
|
||||||
|
{
|
||||||
MSG *msg = findMSG( hash_string( msgid ) );
|
MSG *msg = findMSG( hash_string( msgid ) );
|
||||||
if ( msg && msg->msgstr ) return msg->msgstr;
|
if ( msg && msg->msgstr ) return msg->msgstr;
|
||||||
return msgid;
|
return msgid;
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
#define _GETTEXT_H_
|
#define _GETTEXT_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,20 +34,24 @@
|
|||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
Functions to deal with little endian values stored in uint8_t arrays
|
Functions to deal with little endian values stored in uint8_t arrays
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
|
||||||
|
{
|
||||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
||||||
|
{
|
||||||
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
|
||||||
|
{
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset] = ( uint8_t ) value;
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
||||||
|
{
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset] = ( uint8_t ) value;
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
item[offset + 2] = ( uint8_t )( value >> 16 );
|
||||||
|
@ -42,7 +42,8 @@
|
|||||||
#define PAGE_SECTORS 64
|
#define PAGE_SECTORS 64
|
||||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int last_access;
|
unsigned int last_access;
|
||||||
@ -50,7 +51,8 @@ typedef struct {
|
|||||||
uint8_t* cache;
|
uint8_t* cache;
|
||||||
} CACHE_ENTRY;
|
} CACHE_ENTRY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const DISC_INTERFACE* disc;
|
const DISC_INTERFACE* disc;
|
||||||
sec_t endOfPartition;
|
sec_t endOfPartition;
|
||||||
unsigned int numberOfPages;
|
unsigned int numberOfPages;
|
||||||
@ -99,14 +101,16 @@ bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void*
|
|||||||
/*
|
/*
|
||||||
Read a full sector from the cache
|
Read a full sector from the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) {
|
static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
|
||||||
|
{
|
||||||
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write a full sector to the cache
|
Write a full sector to the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) {
|
static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
|
||||||
|
{
|
||||||
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -59,13 +59,15 @@
|
|||||||
|
|
||||||
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint32_t cluster;
|
uint32_t cluster;
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
int32_t offset;
|
int32_t offset;
|
||||||
} DIR_ENTRY_POSITION;
|
} DIR_ENTRY_POSITION;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
||||||
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
|
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
|
||||||
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
|
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
|
||||||
@ -73,7 +75,8 @@ typedef struct {
|
|||||||
} DIR_ENTRY;
|
} DIR_ENTRY;
|
||||||
|
|
||||||
// Directory entry offsets
|
// Directory entry offsets
|
||||||
enum DIR_ENTRY_offset {
|
enum DIR_ENTRY_offset
|
||||||
|
{
|
||||||
DIR_ENTRY_name = 0x00,
|
DIR_ENTRY_name = 0x00,
|
||||||
DIR_ENTRY_extension = 0x08,
|
DIR_ENTRY_extension = 0x08,
|
||||||
DIR_ENTRY_attributes = 0x0B,
|
DIR_ENTRY_attributes = 0x0B,
|
||||||
@ -92,15 +95,18 @@ enum DIR_ENTRY_offset {
|
|||||||
/*
|
/*
|
||||||
Returns true if the file specified by entry is a directory
|
Returns true if the file specified by entry is a directory
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) {
|
static inline bool _FAT_directory_isDirectory ( DIR_ENTRY* entry )
|
||||||
|
{
|
||||||
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR ) != 0 );
|
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR ) != 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) {
|
static inline bool _FAT_directory_isWritable ( DIR_ENTRY* entry )
|
||||||
|
{
|
||||||
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO ) == 0 );
|
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO ) == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) {
|
static inline bool _FAT_directory_isDot ( DIR_ENTRY* entry )
|
||||||
|
{
|
||||||
return ( ( entry->filename[0] == '.' ) && ( ( entry->filename[1] == '\0' ) ||
|
return ( ( entry->filename[0] == '.' ) && ( ( entry->filename[1] == '\0' ) ||
|
||||||
( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) );
|
( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) );
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,8 @@
|
|||||||
A list of all default devices to try at startup,
|
A list of all default devices to try at startup,
|
||||||
terminated by a {NULL,NULL} entry.
|
terminated by a {NULL,NULL} entry.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
const DISC_INTERFACE* ( *getInterface )( void );
|
const DISC_INTERFACE* ( *getInterface )( void );
|
||||||
} INTERFACE_ID;
|
} INTERFACE_ID;
|
||||||
@ -45,7 +46,8 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
|
|||||||
Check if a disc is inserted
|
Check if a disc is inserted
|
||||||
Return true if a disc is inserted and ready, false otherwise
|
Return true if a disc is inserted and ready, false otherwise
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->isInserted();
|
return disc->isInserted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +58,8 @@ else it is at least 1
|
|||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to fill
|
buffer is a pointer to the memory to fill
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) {
|
static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
|
||||||
|
{
|
||||||
return disc->readSectors ( sector, numSectors, buffer );
|
return disc->readSectors ( sector, numSectors, buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,21 +70,24 @@ else it is at least 1
|
|||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to read from
|
buffer is a pointer to the memory to read from
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) {
|
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||||
|
{
|
||||||
return disc->writeSectors ( sector, numSectors, buffer );
|
return disc->writeSectors ( sector, numSectors, buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reset the card back to a ready state
|
Reset the card back to a ready state
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->clearStatus();
|
return disc->clearStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise the disc to a state ready for data reading or writing
|
Initialise the disc to a state ready for data reading or writing
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->startup();
|
return disc->startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
|||||||
Put the disc in a state ready for power down.
|
Put the disc in a state ready for power down.
|
||||||
Complete any pending writes and disable the disc if necessary
|
Complete any pending writes and disable the disc if necessary
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->shutdown();
|
return disc->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value unique to each type of interface
|
Return a 32 bit value unique to each type of interface
|
||||||
*/
|
*/
|
||||||
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) {
|
static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->ioType;
|
return disc->ioType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value that specifies the capabilities of the disc
|
Return a 32 bit value that specifies the capabilities of the disc
|
||||||
*/
|
*/
|
||||||
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) {
|
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->features;
|
return disc->features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,21 +43,26 @@ The list is terminated by a NULL/NULL entry.
|
|||||||
#include "usbloader/usbstorage2.h"
|
#include "usbloader/usbstorage2.h"
|
||||||
#include <sdcard/gcsd.h>
|
#include <sdcard/gcsd.h>
|
||||||
|
|
||||||
static const DISC_INTERFACE* get_io_wiisd (void) {
|
static const DISC_INTERFACE* get_io_wiisd ( void )
|
||||||
|
{
|
||||||
return &__io_wiisd;
|
return &__io_wiisd;
|
||||||
}
|
}
|
||||||
static const DISC_INTERFACE* get_io_usbstorage (void) {
|
static const DISC_INTERFACE* get_io_usbstorage ( void )
|
||||||
|
{
|
||||||
return &__io_usbstorage2;
|
return &__io_usbstorage2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const DISC_INTERFACE* get_io_gcsda (void) {
|
static const DISC_INTERFACE* get_io_gcsda ( void )
|
||||||
|
{
|
||||||
return &__io_gcsda;
|
return &__io_gcsda;
|
||||||
}
|
}
|
||||||
static const DISC_INTERFACE* get_io_gcsdb (void) {
|
static const DISC_INTERFACE* get_io_gcsdb ( void )
|
||||||
|
{
|
||||||
return &__io_gcsdb;
|
return &__io_gcsdb;
|
||||||
}
|
}
|
||||||
|
|
||||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
const INTERFACE_ID _FAT_disc_interfaces[] =
|
||||||
|
{
|
||||||
{"sd", get_io_wiisd},
|
{"sd", get_io_wiisd},
|
||||||
{"usb", get_io_usbstorage},
|
{"usb", get_io_usbstorage},
|
||||||
{"carda", get_io_gcsda},
|
{"carda", get_io_gcsda},
|
||||||
|
@ -35,7 +35,8 @@
|
|||||||
A list of all default devices to try at startup,
|
A list of all default devices to try at startup,
|
||||||
terminated by a {NULL,NULL} entry.
|
terminated by a {NULL,NULL} entry.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
const DISC_INTERFACE* ( *getInterface )( void );
|
const DISC_INTERFACE* ( *getInterface )( void );
|
||||||
} INTERFACE_ID;
|
} INTERFACE_ID;
|
||||||
@ -45,7 +46,8 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
|
|||||||
Check if a disc is inserted
|
Check if a disc is inserted
|
||||||
Return true if a disc is inserted and ready, false otherwise
|
Return true if a disc is inserted and ready, false otherwise
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->isInserted();
|
return disc->isInserted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +58,8 @@ else it is at least 1
|
|||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to fill
|
buffer is a pointer to the memory to fill
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) {
|
static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
|
||||||
|
{
|
||||||
return disc->readSectors ( sector, numSectors, buffer );
|
return disc->readSectors ( sector, numSectors, buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,21 +70,24 @@ else it is at least 1
|
|||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to read from
|
buffer is a pointer to the memory to read from
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) {
|
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||||
|
{
|
||||||
return disc->writeSectors ( sector, numSectors, buffer );
|
return disc->writeSectors ( sector, numSectors, buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reset the card back to a ready state
|
Reset the card back to a ready state
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->clearStatus();
|
return disc->clearStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise the disc to a state ready for data reading or writing
|
Initialise the disc to a state ready for data reading or writing
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->startup();
|
return disc->startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
|||||||
Put the disc in a state ready for power down.
|
Put the disc in a state ready for power down.
|
||||||
Complete any pending writes and disable the disc if necessary
|
Complete any pending writes and disable the disc if necessary
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) {
|
static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->shutdown();
|
return disc->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value unique to each type of interface
|
Return a 32 bit value unique to each type of interface
|
||||||
*/
|
*/
|
||||||
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) {
|
static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->ioType;
|
return disc->ioType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value that specifies the capabilities of the disc
|
Return a 32 bit value that specifies the capabilities of the disc
|
||||||
*/
|
*/
|
||||||
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) {
|
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||||
|
{
|
||||||
return disc->features;
|
return disc->features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@
|
|||||||
#define _LIBFAT_H
|
#define _LIBFAT_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -46,21 +46,25 @@
|
|||||||
|
|
||||||
#define CACHE_FREE UINT_MAX
|
#define CACHE_FREE UINT_MAX
|
||||||
|
|
||||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition) {
|
CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition )
|
||||||
|
{
|
||||||
CACHE* cache;
|
CACHE* cache;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
CACHE_ENTRY* cacheEntries;
|
CACHE_ENTRY* cacheEntries;
|
||||||
|
|
||||||
if (numberOfPages < 2) {
|
if ( numberOfPages < 2 )
|
||||||
|
{
|
||||||
numberOfPages = 2;
|
numberOfPages = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sectorsPerPage < 8) {
|
if ( sectorsPerPage < 8 )
|
||||||
|
{
|
||||||
sectorsPerPage = 8;
|
sectorsPerPage = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) );
|
cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) );
|
||||||
if (cache == NULL) {
|
if ( cache == NULL )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,12 +75,14 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsP
|
|||||||
|
|
||||||
|
|
||||||
cacheEntries = ( CACHE_ENTRY* ) _FAT_mem_allocate ( sizeof( CACHE_ENTRY ) * numberOfPages );
|
cacheEntries = ( CACHE_ENTRY* ) _FAT_mem_allocate ( sizeof( CACHE_ENTRY ) * numberOfPages );
|
||||||
if (cacheEntries == NULL) {
|
if ( cacheEntries == NULL )
|
||||||
|
{
|
||||||
_FAT_mem_free ( cache );
|
_FAT_mem_free ( cache );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < numberOfPages; i++) {
|
for ( i = 0; i < numberOfPages; i++ )
|
||||||
|
{
|
||||||
cacheEntries[i].sector = CACHE_FREE;
|
cacheEntries[i].sector = CACHE_FREE;
|
||||||
cacheEntries[i].count = 0;
|
cacheEntries[i].count = 0;
|
||||||
cacheEntries[i].last_access = 0;
|
cacheEntries[i].last_access = 0;
|
||||||
@ -89,13 +95,15 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsP
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _FAT_cache_destructor (CACHE* cache) {
|
void _FAT_cache_destructor ( CACHE* cache )
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
// Clear out cache before destroying it
|
// Clear out cache before destroying it
|
||||||
_FAT_cache_flush( cache );
|
_FAT_cache_flush( cache );
|
||||||
|
|
||||||
// Free memory in reverse allocation order
|
// Free memory in reverse allocation order
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||||
|
{
|
||||||
_FAT_mem_free ( cache->cacheEntries[i].cache );
|
_FAT_mem_free ( cache->cacheEntries[i].cache );
|
||||||
}
|
}
|
||||||
_FAT_mem_free ( cache->cacheEntries );
|
_FAT_mem_free ( cache->cacheEntries );
|
||||||
@ -105,7 +113,8 @@ void _FAT_cache_destructor (CACHE* cache) {
|
|||||||
|
|
||||||
static u32 accessCounter = 0;
|
static u32 accessCounter = 0;
|
||||||
|
|
||||||
static u32 accessTime(){
|
static u32 accessTime()
|
||||||
|
{
|
||||||
accessCounter++;
|
accessCounter++;
|
||||||
return accessCounter;
|
return accessCounter;
|
||||||
}
|
}
|
||||||
@ -122,20 +131,24 @@ static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector)
|
|||||||
unsigned int oldUsed = 0;
|
unsigned int oldUsed = 0;
|
||||||
unsigned int oldAccess = UINT_MAX;
|
unsigned int oldAccess = UINT_MAX;
|
||||||
|
|
||||||
for(i=0;i<numberOfPages;i++) {
|
for ( i = 0; i < numberOfPages; i++ )
|
||||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
{
|
||||||
|
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
||||||
|
{
|
||||||
cacheEntries[i].last_access = accessTime();
|
cacheEntries[i].last_access = accessTime();
|
||||||
return &( cacheEntries[i] );
|
return &( cacheEntries[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
||||||
|
{
|
||||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
||||||
oldUsed = i;
|
oldUsed = i;
|
||||||
oldAccess = cacheEntries[i].last_access;
|
oldAccess = cacheEntries[i].last_access;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
||||||
|
{
|
||||||
if ( !_FAT_disc_writeSectors( cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
if ( !_FAT_disc_writeSectors( cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||||
cacheEntries[oldUsed].dirty = false;
|
cacheEntries[oldUsed].dirty = false;
|
||||||
}
|
}
|
||||||
@ -160,7 +173,8 @@ bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buf
|
|||||||
CACHE_ENTRY *entry;
|
CACHE_ENTRY *entry;
|
||||||
uint8_t *dest = buffer;
|
uint8_t *dest = buffer;
|
||||||
|
|
||||||
while(numSectors>0) {
|
while ( numSectors > 0 )
|
||||||
|
{
|
||||||
entry = _FAT_cache_getPage( cache, sector );
|
entry = _FAT_cache_getPage( cache, sector );
|
||||||
if ( entry == NULL ) return false;
|
if ( entry == NULL ) return false;
|
||||||
|
|
||||||
@ -197,11 +211,13 @@ bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, uns
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
bool _FAT_cache_readLittleEndianValue ( CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
|
||||||
|
{
|
||||||
uint8_t buf[4];
|
uint8_t buf[4];
|
||||||
if ( !_FAT_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
if ( !_FAT_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||||
|
|
||||||
switch(num_bytes) {
|
switch ( num_bytes )
|
||||||
|
{
|
||||||
case 1: *value = buf[0]; break;
|
case 1: *value = buf[0]; break;
|
||||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||||
@ -230,10 +246,12 @@ bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sect
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
||||||
|
{
|
||||||
uint8_t buf[4] = {0, 0, 0, 0};
|
uint8_t buf[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
switch(size) {
|
switch ( size )
|
||||||
|
{
|
||||||
case 1: buf[0] = value; break;
|
case 1: buf[0] = value; break;
|
||||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||||
@ -265,7 +283,8 @@ bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count) {
|
static CACHE_ENTRY* _FAT_cache_findPage( CACHE *cache, sec_t sector, sec_t count )
|
||||||
|
{
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
@ -273,16 +292,22 @@ static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count)
|
|||||||
CACHE_ENTRY *entry = NULL;
|
CACHE_ENTRY *entry = NULL;
|
||||||
sec_t lowest = UINT_MAX;
|
sec_t lowest = UINT_MAX;
|
||||||
|
|
||||||
for(i=0;i<numberOfPages;i++) {
|
for ( i = 0; i < numberOfPages; i++ )
|
||||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
{
|
||||||
|
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||||
|
{
|
||||||
bool intersect;
|
bool intersect;
|
||||||
if (sector > cacheEntries[i].sector) {
|
if ( sector > cacheEntries[i].sector )
|
||||||
|
{
|
||||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
intersect = cacheEntries[i].sector - sector < count;
|
intersect = cacheEntries[i].sector - sector < count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||||
|
{
|
||||||
lowest = cacheEntries[i].sector;
|
lowest = cacheEntries[i].sector;
|
||||||
entry = &cacheEntries[i];
|
entry = &cacheEntries[i];
|
||||||
}
|
}
|
||||||
@ -303,9 +328,11 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
|
|||||||
{
|
{
|
||||||
entry = _FAT_cache_findPage( cache, sector, numSectors );
|
entry = _FAT_cache_findPage( cache, sector, numSectors );
|
||||||
|
|
||||||
if(entry!=NULL) {
|
if ( entry != NULL )
|
||||||
|
{
|
||||||
|
|
||||||
if ( entry->sector > sector) {
|
if ( entry->sector > sector )
|
||||||
|
{
|
||||||
|
|
||||||
secs_to_write = entry->sector - sector;
|
secs_to_write = entry->sector - sector;
|
||||||
|
|
||||||
@ -328,7 +355,9 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
|
|||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_FAT_disc_writeSectors( cache->disc, sector, numSectors, src );
|
_FAT_disc_writeSectors( cache->disc, sector, numSectors, src );
|
||||||
numSectors = 0;
|
numSectors = 0;
|
||||||
}
|
}
|
||||||
@ -339,12 +368,16 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
|
|||||||
/*
|
/*
|
||||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||||
*/
|
*/
|
||||||
bool _FAT_cache_flush (CACHE* cache) {
|
bool _FAT_cache_flush ( CACHE* cache )
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||||
if (cache->cacheEntries[i].dirty) {
|
{
|
||||||
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
if ( cache->cacheEntries[i].dirty )
|
||||||
|
{
|
||||||
|
if ( !_FAT_disc_writeSectors ( cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,10 +387,12 @@ bool _FAT_cache_flush (CACHE* cache) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _FAT_cache_invalidate (CACHE* cache) {
|
void _FAT_cache_invalidate ( CACHE* cache )
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
_FAT_cache_flush( cache );
|
_FAT_cache_flush( cache );
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||||
|
{
|
||||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||||
cache->cacheEntries[i].last_access = 0;
|
cache->cacheEntries[i].last_access = 0;
|
||||||
cache->cacheEntries[i].count = 0;
|
cache->cacheEntries[i].count = 0;
|
||||||
|
@ -42,7 +42,8 @@
|
|||||||
#define PAGE_SECTORS 64
|
#define PAGE_SECTORS 64
|
||||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int last_access;
|
unsigned int last_access;
|
||||||
@ -50,7 +51,8 @@ typedef struct {
|
|||||||
uint8_t* cache;
|
uint8_t* cache;
|
||||||
} CACHE_ENTRY;
|
} CACHE_ENTRY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const DISC_INTERFACE* disc;
|
const DISC_INTERFACE* disc;
|
||||||
sec_t endOfPartition;
|
sec_t endOfPartition;
|
||||||
unsigned int numberOfPages;
|
unsigned int numberOfPages;
|
||||||
@ -99,14 +101,16 @@ bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void*
|
|||||||
/*
|
/*
|
||||||
Read a full sector from the cache
|
Read a full sector from the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) {
|
static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
|
||||||
|
{
|
||||||
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write a full sector to the cache
|
Write a full sector to the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) {
|
static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
|
||||||
|
{
|
||||||
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,22 +45,26 @@
|
|||||||
#include "lock.h"
|
#include "lock.h"
|
||||||
|
|
||||||
|
|
||||||
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
|
int _FAT_stat_r ( struct _reent *r, const char *path, struct stat *st )
|
||||||
|
{
|
||||||
PARTITION* partition = NULL;
|
PARTITION* partition = NULL;
|
||||||
DIR_ENTRY dirEntry;
|
DIR_ENTRY dirEntry;
|
||||||
|
|
||||||
// Get the partition this file is on
|
// Get the partition this file is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||||
if (partition == NULL) {
|
if ( partition == NULL )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr ( path, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -68,7 +72,8 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
|
|||||||
_FAT_lock( &partition->lock );
|
_FAT_lock( &partition->lock );
|
||||||
|
|
||||||
// Search for the file on the disc
|
// Search for the file on the disc
|
||||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) {
|
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -81,12 +86,14 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink) {
|
int _FAT_link_r ( struct _reent *r, const char *existing, const char *newLink )
|
||||||
|
{
|
||||||
r->_errno = ENOTSUP;
|
r->_errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_unlink_r (struct _reent *r, const char *path) {
|
int _FAT_unlink_r ( struct _reent *r, const char *path )
|
||||||
|
{
|
||||||
PARTITION* partition = NULL;
|
PARTITION* partition = NULL;
|
||||||
DIR_ENTRY dirEntry;
|
DIR_ENTRY dirEntry;
|
||||||
DIR_ENTRY dirContents;
|
DIR_ENTRY dirContents;
|
||||||
@ -96,22 +103,26 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
|
|||||||
|
|
||||||
// Get the partition this directory is on
|
// Get the partition this directory is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||||
if (partition == NULL) {
|
if ( partition == NULL )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we aren't trying to write to a read-only disc
|
// Make sure we aren't trying to write to a read-only disc
|
||||||
if (partition->readOnly) {
|
if ( partition->readOnly )
|
||||||
|
{
|
||||||
r->_errno = EROFS;
|
r->_errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr ( path, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -119,7 +130,8 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
|
|||||||
_FAT_lock( &partition->lock );
|
_FAT_lock( &partition->lock );
|
||||||
|
|
||||||
// Search for the file on the disc
|
// Search for the file on the disc
|
||||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) {
|
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -129,11 +141,14 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
|
|||||||
|
|
||||||
|
|
||||||
// If this is a directory, make sure it is empty
|
// If this is a directory, make sure it is empty
|
||||||
if (_FAT_directory_isDirectory (&dirEntry)) {
|
if ( _FAT_directory_isDirectory ( &dirEntry ) )
|
||||||
|
{
|
||||||
nextEntry = _FAT_directory_getFirstEntry ( partition, &dirContents, cluster );
|
nextEntry = _FAT_directory_getFirstEntry ( partition, &dirContents, cluster );
|
||||||
|
|
||||||
while (nextEntry) {
|
while ( nextEntry )
|
||||||
if (!_FAT_directory_isDot (&dirContents)) {
|
{
|
||||||
|
if ( !_FAT_directory_isDot ( &dirContents ) )
|
||||||
|
{
|
||||||
// The directory had something in it that isn't a reference to itself or it's parent
|
// The directory had something in it that isn't a reference to itself or it's parent
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EPERM;
|
r->_errno = EPERM;
|
||||||
@ -143,49 +158,60 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_FAT_fat_isValidCluster(partition, cluster)) {
|
if ( _FAT_fat_isValidCluster( partition, cluster ) )
|
||||||
|
{
|
||||||
// Remove the cluster chain for this file
|
// Remove the cluster chain for this file
|
||||||
if (!_FAT_fat_clearLinks (partition, cluster)) {
|
if ( !_FAT_fat_clearLinks ( partition, cluster ) )
|
||||||
|
{
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
errorOccured = true;
|
errorOccured = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the directory entry for this file
|
// Remove the directory entry for this file
|
||||||
if (!_FAT_directory_removeEntry (partition, &dirEntry)) {
|
if ( !_FAT_directory_removeEntry ( partition, &dirEntry ) )
|
||||||
|
{
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
errorOccured = true;
|
errorOccured = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush any sectors in the disc cache
|
// Flush any sectors in the disc cache
|
||||||
if (!_FAT_cache_flush(partition->cache)) {
|
if ( !_FAT_cache_flush( partition->cache ) )
|
||||||
|
{
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
errorOccured = true;
|
errorOccured = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
if (errorOccured) {
|
if ( errorOccured )
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_chdir_r (struct _reent *r, const char *path) {
|
int _FAT_chdir_r ( struct _reent *r, const char *path )
|
||||||
|
{
|
||||||
PARTITION* partition = NULL;
|
PARTITION* partition = NULL;
|
||||||
|
|
||||||
// Get the partition this directory is on
|
// Get the partition this directory is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||||
if (partition == NULL) {
|
if ( partition == NULL )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr ( path, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -193,11 +219,14 @@ int _FAT_chdir_r (struct _reent *r, const char *path) {
|
|||||||
_FAT_lock( &partition->lock );
|
_FAT_lock( &partition->lock );
|
||||||
|
|
||||||
// Try changing directory
|
// Try changing directory
|
||||||
if (_FAT_directory_chdir (partition, path)) {
|
if ( _FAT_directory_chdir ( partition, path ) )
|
||||||
|
{
|
||||||
// Successful
|
// Successful
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Failed
|
// Failed
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
@ -205,7 +234,8 @@ int _FAT_chdir_r (struct _reent *r, const char *path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName )
|
||||||
|
{
|
||||||
PARTITION* partition = NULL;
|
PARTITION* partition = NULL;
|
||||||
DIR_ENTRY oldDirEntry;
|
DIR_ENTRY oldDirEntry;
|
||||||
DIR_ENTRY newDirEntry;
|
DIR_ENTRY newDirEntry;
|
||||||
@ -214,7 +244,8 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
|||||||
|
|
||||||
// Get the partition this directory is on
|
// Get the partition this directory is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( oldName );
|
partition = _FAT_partition_getPartitionFromPath ( oldName );
|
||||||
if (partition == NULL) {
|
if ( partition == NULL )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -222,46 +253,54 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
|||||||
_FAT_lock( &partition->lock );
|
_FAT_lock( &partition->lock );
|
||||||
|
|
||||||
// Make sure the same partition is used for the old and new names
|
// Make sure the same partition is used for the old and new names
|
||||||
if (partition != _FAT_partition_getPartitionFromPath (newName)) {
|
if ( partition != _FAT_partition_getPartitionFromPath ( newName ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EXDEV;
|
r->_errno = EXDEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we aren't trying to write to a read-only disc
|
// Make sure we aren't trying to write to a read-only disc
|
||||||
if (partition->readOnly) {
|
if ( partition->readOnly )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EROFS;
|
r->_errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if (strchr (oldName, ':') != NULL) {
|
if ( strchr ( oldName, ':' ) != NULL )
|
||||||
|
{
|
||||||
oldName = strchr ( oldName, ':' ) + 1;
|
oldName = strchr ( oldName, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr (oldName, ':') != NULL) {
|
if ( strchr ( oldName, ':' ) != NULL )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (strchr (newName, ':') != NULL) {
|
if ( strchr ( newName, ':' ) != NULL )
|
||||||
|
{
|
||||||
newName = strchr ( newName, ':' ) + 1;
|
newName = strchr ( newName, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr (newName, ':') != NULL) {
|
if ( strchr ( newName, ':' ) != NULL )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for the file on the disc
|
// Search for the file on the disc
|
||||||
if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL)) {
|
if ( !_FAT_directory_entryFromPath ( partition, &oldDirEntry, oldName, NULL ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there is no existing file / directory with the new name
|
// Make sure there is no existing file / directory with the new name
|
||||||
if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL)) {
|
if ( _FAT_directory_entryFromPath ( partition, &newDirEntry, newName, NULL ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
return -1;
|
return -1;
|
||||||
@ -270,15 +309,19 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
|||||||
// Create the new file entry
|
// Create the new file entry
|
||||||
// Get the directory it has to go in
|
// Get the directory it has to go in
|
||||||
pathEnd = strrchr ( newName, DIR_SEPARATOR );
|
pathEnd = strrchr ( newName, DIR_SEPARATOR );
|
||||||
if (pathEnd == NULL) {
|
if ( pathEnd == NULL )
|
||||||
|
{
|
||||||
// No path was specified
|
// No path was specified
|
||||||
dirCluster = partition->cwdCluster;
|
dirCluster = partition->cwdCluster;
|
||||||
pathEnd = newName;
|
pathEnd = newName;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Path was specified -- get the right dirCluster
|
// Path was specified -- get the right dirCluster
|
||||||
// Recycling newDirEntry, since it needs to be recreated anyway
|
// Recycling newDirEntry, since it needs to be recreated anyway
|
||||||
if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) ||
|
if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) ||
|
||||||
!_FAT_directory_isDirectory(&newDirEntry)) {
|
!_FAT_directory_isDirectory( &newDirEntry ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return -1;
|
return -1;
|
||||||
@ -295,21 +338,24 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
|||||||
strncpy ( newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 );
|
strncpy ( newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 );
|
||||||
|
|
||||||
// Write the new entry
|
// Write the new entry
|
||||||
if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster)) {
|
if ( !_FAT_directory_addEntry ( partition, &newDirEntry, dirCluster ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOSPC;
|
r->_errno = ENOSPC;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the old entry
|
// Remove the old entry
|
||||||
if (!_FAT_directory_removeEntry (partition, &oldDirEntry)) {
|
if ( !_FAT_directory_removeEntry ( partition, &oldDirEntry ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush any sectors in the disc cache
|
// Flush any sectors in the disc cache
|
||||||
if (!_FAT_cache_flush (partition->cache)) {
|
if ( !_FAT_cache_flush ( partition->cache ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -319,7 +365,8 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
|
||||||
|
{
|
||||||
PARTITION* partition = NULL;
|
PARTITION* partition = NULL;
|
||||||
bool fileExists;
|
bool fileExists;
|
||||||
DIR_ENTRY dirEntry;
|
DIR_ENTRY dirEntry;
|
||||||
@ -328,16 +375,19 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
|||||||
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
||||||
|
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||||
if (partition == NULL) {
|
if ( partition == NULL )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr ( path, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -348,13 +398,15 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
|||||||
fileExists = _FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL );
|
fileExists = _FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL );
|
||||||
|
|
||||||
// Make sure it doesn't exist
|
// Make sure it doesn't exist
|
||||||
if (fileExists) {
|
if ( fileExists )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partition->readOnly) {
|
if ( partition->readOnly )
|
||||||
|
{
|
||||||
// We can't write to a read-only partition
|
// We can't write to a read-only partition
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EROFS;
|
r->_errno = EROFS;
|
||||||
@ -363,15 +415,19 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
|||||||
|
|
||||||
// Get the directory it has to go in
|
// Get the directory it has to go in
|
||||||
pathEnd = strrchr ( path, DIR_SEPARATOR );
|
pathEnd = strrchr ( path, DIR_SEPARATOR );
|
||||||
if (pathEnd == NULL) {
|
if ( pathEnd == NULL )
|
||||||
|
{
|
||||||
// No path was specified
|
// No path was specified
|
||||||
parentCluster = partition->cwdCluster;
|
parentCluster = partition->cwdCluster;
|
||||||
pathEnd = path;
|
pathEnd = path;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Path was specified -- get the right parentCluster
|
// Path was specified -- get the right parentCluster
|
||||||
// Recycling dirEntry, since it needs to be recreated anyway
|
// Recycling dirEntry, since it needs to be recreated anyway
|
||||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
|
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
|
||||||
!_FAT_directory_isDirectory(&dirEntry)) {
|
!_FAT_directory_isDirectory( &dirEntry ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return -1;
|
return -1;
|
||||||
@ -397,7 +453,8 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
|||||||
|
|
||||||
// Get a cluster for the new directory
|
// Get a cluster for the new directory
|
||||||
dirCluster = _FAT_fat_linkFreeClusterCleared ( partition, CLUSTER_FREE );
|
dirCluster = _FAT_fat_linkFreeClusterCleared ( partition, CLUSTER_FREE );
|
||||||
if (!_FAT_fat_isValidCluster(partition, dirCluster)) {
|
if ( !_FAT_fat_isValidCluster( partition, dirCluster ) )
|
||||||
|
{
|
||||||
// No space left on disc for the cluster
|
// No space left on disc for the cluster
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOSPC;
|
r->_errno = ENOSPC;
|
||||||
@ -407,7 +464,8 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
|||||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16 );
|
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16 );
|
||||||
|
|
||||||
// Write the new directory's entry to it's parent
|
// Write the new directory's entry to it's parent
|
||||||
if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster)) {
|
if ( !_FAT_directory_addEntry ( partition, &dirEntry, parentCluster ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = ENOSPC;
|
r->_errno = ENOSPC;
|
||||||
return -1;
|
return -1;
|
||||||
@ -441,7 +499,8 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
|||||||
_FAT_fat_clusterToSector ( partition, dirCluster ), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
_FAT_fat_clusterToSector ( partition, dirCluster ), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||||
|
|
||||||
// Flush any sectors in the disc cache
|
// Flush any sectors in the disc cache
|
||||||
if (!_FAT_cache_flush(partition->cache)) {
|
if ( !_FAT_cache_flush( partition->cache ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock( &partition->lock );
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -458,7 +517,8 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
|||||||
|
|
||||||
// Get the partition of the requested path
|
// Get the partition of the requested path
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||||
if (partition == NULL) {
|
if ( partition == NULL )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -493,22 +553,26 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) {
|
DIR_ITER* _FAT_diropen_r( struct _reent *r, DIR_ITER *dirState, const char *path )
|
||||||
|
{
|
||||||
DIR_ENTRY dirEntry;
|
DIR_ENTRY dirEntry;
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||||
bool fileExists;
|
bool fileExists;
|
||||||
|
|
||||||
state->partition = _FAT_partition_getPartitionFromPath ( path );
|
state->partition = _FAT_partition_getPartitionFromPath ( path );
|
||||||
if (state->partition == NULL) {
|
if ( state->partition == NULL )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr ( path, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr (path, ':') != NULL) {
|
if ( strchr ( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -518,14 +582,16 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
|
|||||||
// Get the start cluster of the directory
|
// Get the start cluster of the directory
|
||||||
fileExists = _FAT_directory_entryFromPath ( state->partition, &dirEntry, path, NULL );
|
fileExists = _FAT_directory_entryFromPath ( state->partition, &dirEntry, path, NULL );
|
||||||
|
|
||||||
if (!fileExists) {
|
if ( !fileExists )
|
||||||
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock( &state->partition->lock );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure it is a directory
|
// Make sure it is a directory
|
||||||
if (! _FAT_directory_isDirectory (&dirEntry)) {
|
if ( ! _FAT_directory_isDirectory ( &dirEntry ) )
|
||||||
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock( &state->partition->lock );
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -544,13 +610,15 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
|
|||||||
return ( DIR_ITER* ) state;
|
return ( DIR_ITER* ) state;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) {
|
int _FAT_dirreset_r ( struct _reent *r, DIR_ITER *dirState )
|
||||||
|
{
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||||
|
|
||||||
_FAT_lock( &state->partition->lock );
|
_FAT_lock( &state->partition->lock );
|
||||||
|
|
||||||
// Make sure we are still using this entry
|
// Make sure we are still using this entry
|
||||||
if (!state->inUse) {
|
if ( !state->inUse )
|
||||||
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock( &state->partition->lock );
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
@ -564,20 +632,23 @@ int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) {
|
int _FAT_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat )
|
||||||
|
{
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||||
|
|
||||||
_FAT_lock( &state->partition->lock );
|
_FAT_lock( &state->partition->lock );
|
||||||
|
|
||||||
// Make sure we are still using this entry
|
// Make sure we are still using this entry
|
||||||
if (!state->inUse) {
|
if ( !state->inUse )
|
||||||
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock( &state->partition->lock );
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there is another file to report on
|
// Make sure there is another file to report on
|
||||||
if (! state->validEntry) {
|
if ( ! state->validEntry )
|
||||||
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock( &state->partition->lock );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -586,7 +657,8 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
|||||||
// Get the filename
|
// Get the filename
|
||||||
strncpy ( filename, state->currentEntry.filename, MAX_FILENAME_LENGTH );
|
strncpy ( filename, state->currentEntry.filename, MAX_FILENAME_LENGTH );
|
||||||
// Get the stats, if requested
|
// Get the stats, if requested
|
||||||
if (filestat != NULL) {
|
if ( filestat != NULL )
|
||||||
|
{
|
||||||
_FAT_directory_entryStat ( state->partition, &( state->currentEntry ), filestat );
|
_FAT_directory_entryStat ( state->partition, &( state->currentEntry ), filestat );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,7 +670,8 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState) {
|
int _FAT_dirclose_r ( struct _reent *r, DIR_ITER *dirState )
|
||||||
|
{
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||||
|
|
||||||
// We are no longer using this entry
|
// We are no longer using this entry
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "directory.h"
|
#include "directory.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
DIR_ENTRY currentEntry;
|
DIR_ENTRY currentEntry;
|
||||||
uint32_t startCluster;
|
uint32_t startCluster;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -41,7 +41,8 @@
|
|||||||
|
|
||||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 cluster;
|
u32 cluster;
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
s32 byte;
|
s32 byte;
|
||||||
@ -49,7 +50,8 @@ typedef struct {
|
|||||||
|
|
||||||
struct _FILE_STRUCT;
|
struct _FILE_STRUCT;
|
||||||
|
|
||||||
struct _FILE_STRUCT {
|
struct _FILE_STRUCT
|
||||||
|
{
|
||||||
uint32_t filesize;
|
uint32_t filesize;
|
||||||
uint32_t startCluster;
|
uint32_t startCluster;
|
||||||
uint32_t currentPosition;
|
uint32_t currentPosition;
|
||||||
|
@ -41,7 +41,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
|||||||
sec_t sector;
|
sec_t sector;
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
if (cluster == CLUSTER_FREE) {
|
if ( cluster == CLUSTER_FREE )
|
||||||
|
{
|
||||||
return CLUSTER_FREE;
|
return CLUSTER_FREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +63,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
|||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
|
|
||||||
if (offset >= BYTES_PER_READ) {
|
if ( offset >= BYTES_PER_READ )
|
||||||
|
{
|
||||||
offset = 0;
|
offset = 0;
|
||||||
sector++;
|
sector++;
|
||||||
}
|
}
|
||||||
@ -71,9 +73,12 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
|||||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster_h, sector, offset, sizeof( u8 ) );
|
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster_h, sector, offset, sizeof( u8 ) );
|
||||||
nextCluster |= ( nextCluster_h << 8 );
|
nextCluster |= ( nextCluster_h << 8 );
|
||||||
|
|
||||||
if (cluster & 0x01) {
|
if ( cluster & 0x01 )
|
||||||
|
{
|
||||||
nextCluster = nextCluster >> 4;
|
nextCluster = nextCluster >> 4;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
nextCluster &= 0x0FFF;
|
nextCluster &= 0x0FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +95,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
|||||||
|
|
||||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u16 ) );
|
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u16 ) );
|
||||||
|
|
||||||
if (nextCluster >= 0xFFF7) {
|
if ( nextCluster >= 0xFFF7 )
|
||||||
|
{
|
||||||
nextCluster = CLUSTER_EOF;
|
nextCluster = CLUSTER_EOF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -101,7 +107,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
|||||||
|
|
||||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u32 ) );
|
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u32 ) );
|
||||||
|
|
||||||
if (nextCluster >= 0x0FFFFFF7) {
|
if ( nextCluster >= 0x0FFFFFF7 )
|
||||||
|
{
|
||||||
nextCluster = CLUSTER_EOF;
|
nextCluster = CLUSTER_EOF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -118,7 +125,8 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
|||||||
writes value into the correct offset within a partition's FAT, based
|
writes value into the correct offset within a partition's FAT, based
|
||||||
on the cluster number.
|
on the cluster number.
|
||||||
*/
|
*/
|
||||||
static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value) {
|
static bool _FAT_fat_writeFatEntry ( PARTITION* partition, uint32_t cluster, uint32_t value )
|
||||||
|
{
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
int offset;
|
int offset;
|
||||||
uint32_t oldValue;
|
uint32_t oldValue;
|
||||||
@ -138,7 +146,8 @@ static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint
|
|||||||
sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ );
|
sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ );
|
||||||
offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ;
|
offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ;
|
||||||
|
|
||||||
if (cluster & 0x01) {
|
if ( cluster & 0x01 )
|
||||||
|
{
|
||||||
|
|
||||||
_FAT_cache_readLittleEndianValue ( partition->cache, &oldValue, sector, offset, sizeof( u8 ) );
|
_FAT_cache_readLittleEndianValue ( partition->cache, &oldValue, sector, offset, sizeof( u8 ) );
|
||||||
|
|
||||||
@ -147,19 +156,23 @@ static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint
|
|||||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value & 0xFF, sector, offset, sizeof( u8 ) );
|
_FAT_cache_writeLittleEndianValue ( partition->cache, value & 0xFF, sector, offset, sizeof( u8 ) );
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
if (offset >= BYTES_PER_READ) {
|
if ( offset >= BYTES_PER_READ )
|
||||||
|
{
|
||||||
offset = 0;
|
offset = 0;
|
||||||
sector++;
|
sector++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_cache_writeLittleEndianValue ( partition->cache, ( value >> 8 ) & 0xFF, sector, offset, sizeof( u8 ) );
|
_FAT_cache_writeLittleEndianValue ( partition->cache, ( value >> 8 ) & 0xFF, sector, offset, sizeof( u8 ) );
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) );
|
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) );
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
if (offset >= BYTES_PER_READ) {
|
if ( offset >= BYTES_PER_READ )
|
||||||
|
{
|
||||||
offset = 0;
|
offset = 0;
|
||||||
sector++;
|
sector++;
|
||||||
}
|
}
|
||||||
@ -203,7 +216,8 @@ to end of file, links the input cluster to it then returns the
|
|||||||
cluster number
|
cluster number
|
||||||
If an error occurs, return CLUSTER_ERROR
|
If an error occurs, return CLUSTER_ERROR
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
|
uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
|
||||||
|
{
|
||||||
uint32_t firstFree;
|
uint32_t firstFree;
|
||||||
uint32_t curLink;
|
uint32_t curLink;
|
||||||
uint32_t lastCluster;
|
uint32_t lastCluster;
|
||||||
@ -211,32 +225,40 @@ uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
|
|||||||
|
|
||||||
lastCluster = partition->fat.lastCluster;
|
lastCluster = partition->fat.lastCluster;
|
||||||
|
|
||||||
if (cluster > lastCluster) {
|
if ( cluster > lastCluster )
|
||||||
|
{
|
||||||
return CLUSTER_ERROR;
|
return CLUSTER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the cluster already has a link, and return it if so
|
// Check if the cluster already has a link, and return it if so
|
||||||
curLink = _FAT_fat_nextCluster( partition, cluster );
|
curLink = _FAT_fat_nextCluster( partition, cluster );
|
||||||
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster)) {
|
if ( ( curLink >= CLUSTER_FIRST ) && ( curLink <= lastCluster ) )
|
||||||
|
{
|
||||||
return curLink; // Return the current link - don't allocate a new one
|
return curLink; // Return the current link - don't allocate a new one
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a free cluster
|
// Get a free cluster
|
||||||
firstFree = partition->fat.firstFree;
|
firstFree = partition->fat.firstFree;
|
||||||
// Start at first valid cluster
|
// Start at first valid cluster
|
||||||
if (firstFree < CLUSTER_FIRST) {
|
if ( firstFree < CLUSTER_FIRST )
|
||||||
|
{
|
||||||
firstFree = CLUSTER_FIRST;
|
firstFree = CLUSTER_FIRST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search until a free cluster is found
|
// Search until a free cluster is found
|
||||||
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) {
|
while ( _FAT_fat_nextCluster( partition, firstFree ) != CLUSTER_FREE )
|
||||||
|
{
|
||||||
firstFree++;
|
firstFree++;
|
||||||
if (firstFree > lastCluster) {
|
if ( firstFree > lastCluster )
|
||||||
if (loopedAroundFAT) {
|
{
|
||||||
|
if ( loopedAroundFAT )
|
||||||
|
{
|
||||||
// If couldn't get a free cluster then return an error
|
// If couldn't get a free cluster then return an error
|
||||||
partition->fat.firstFree = firstFree;
|
partition->fat.firstFree = firstFree;
|
||||||
return CLUSTER_ERROR;
|
return CLUSTER_ERROR;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Try looping back to the beginning of the FAT
|
// Try looping back to the beginning of the FAT
|
||||||
// This was suggested by loopy
|
// This was suggested by loopy
|
||||||
firstFree = CLUSTER_FIRST;
|
firstFree = CLUSTER_FIRST;
|
||||||
@ -263,7 +285,8 @@ to end of file, links the input cluster to it, clears the new
|
|||||||
cluster to 0 valued bytes, then returns the cluster number
|
cluster to 0 valued bytes, then returns the cluster number
|
||||||
If an error occurs, return CLUSTER_ERROR
|
If an error occurs, return CLUSTER_ERROR
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster) {
|
uint32_t _FAT_fat_linkFreeClusterCleared ( PARTITION* partition, uint32_t cluster )
|
||||||
|
{
|
||||||
uint32_t newCluster;
|
uint32_t newCluster;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t emptySector[BYTES_PER_READ];
|
uint8_t emptySector[BYTES_PER_READ];
|
||||||
@ -271,13 +294,15 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster
|
|||||||
// Link the cluster
|
// Link the cluster
|
||||||
newCluster = _FAT_fat_linkFreeCluster( partition, cluster );
|
newCluster = _FAT_fat_linkFreeCluster( partition, cluster );
|
||||||
|
|
||||||
if (newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR) {
|
if ( newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR )
|
||||||
|
{
|
||||||
return CLUSTER_ERROR;
|
return CLUSTER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all the sectors within the cluster
|
// Clear all the sectors within the cluster
|
||||||
memset ( emptySector, 0, BYTES_PER_READ );
|
memset ( emptySector, 0, BYTES_PER_READ );
|
||||||
for (i = 0; i < partition->sectorsPerCluster; i++) {
|
for ( i = 0; i < partition->sectorsPerCluster; i++ )
|
||||||
|
{
|
||||||
_FAT_cache_writeSectors ( partition->cache,
|
_FAT_cache_writeSectors ( partition->cache,
|
||||||
_FAT_fat_clusterToSector ( partition, newCluster ) + i,
|
_FAT_fat_clusterToSector ( partition, newCluster ) + i,
|
||||||
1, emptySector );
|
1, emptySector );
|
||||||
@ -291,18 +316,21 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster
|
|||||||
_FAT_fat_clearLinks
|
_FAT_fat_clearLinks
|
||||||
frees any cluster used by a file
|
frees any cluster used by a file
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster) {
|
bool _FAT_fat_clearLinks ( PARTITION* partition, uint32_t cluster )
|
||||||
|
{
|
||||||
uint32_t nextCluster;
|
uint32_t nextCluster;
|
||||||
|
|
||||||
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
|
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
||||||
if (cluster < partition->fat.firstFree) {
|
if ( cluster < partition->fat.firstFree )
|
||||||
|
{
|
||||||
partition->fat.firstFree = cluster;
|
partition->fat.firstFree = cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR)) {
|
while ( ( cluster != CLUSTER_EOF ) && ( cluster != CLUSTER_FREE ) && ( cluster != CLUSTER_ERROR ) )
|
||||||
|
{
|
||||||
// Store next cluster before erasing the link
|
// Store next cluster before erasing the link
|
||||||
nextCluster = _FAT_fat_nextCluster ( partition, cluster );
|
nextCluster = _FAT_fat_nextCluster ( partition, cluster );
|
||||||
|
|
||||||
@ -324,25 +352,31 @@ If chainLength is 1, the first cluster is kept and the rest are
|
|||||||
dropped, and so on.
|
dropped, and so on.
|
||||||
Return the last cluster left in the chain.
|
Return the last cluster left in the chain.
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength) {
|
uint32_t _FAT_fat_trimChain ( PARTITION* partition, uint32_t startCluster, unsigned int chainLength )
|
||||||
|
{
|
||||||
uint32_t nextCluster;
|
uint32_t nextCluster;
|
||||||
|
|
||||||
if (chainLength == 0) {
|
if ( chainLength == 0 )
|
||||||
|
{
|
||||||
// Drop the entire chain
|
// Drop the entire chain
|
||||||
_FAT_fat_clearLinks ( partition, startCluster );
|
_FAT_fat_clearLinks ( partition, startCluster );
|
||||||
return CLUSTER_FREE;
|
return CLUSTER_FREE;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Find the last cluster in the chain, and the one after it
|
// Find the last cluster in the chain, and the one after it
|
||||||
chainLength--;
|
chainLength--;
|
||||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
||||||
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) {
|
while ( ( chainLength > 0 ) && ( nextCluster != CLUSTER_FREE ) && ( nextCluster != CLUSTER_EOF ) )
|
||||||
|
{
|
||||||
chainLength--;
|
chainLength--;
|
||||||
startCluster = nextCluster;
|
startCluster = nextCluster;
|
||||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop all clusters after the last in the chain
|
// Drop all clusters after the last in the chain
|
||||||
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF) {
|
if ( nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF )
|
||||||
|
{
|
||||||
_FAT_fat_clearLinks ( partition, nextCluster );
|
_FAT_fat_clearLinks ( partition, nextCluster );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,8 +391,10 @@ uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsign
|
|||||||
_FAT_fat_lastCluster
|
_FAT_fat_lastCluster
|
||||||
Trace the cluster links until the last one is found
|
Trace the cluster links until the last one is found
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
|
uint32_t _FAT_fat_lastCluster ( PARTITION* partition, uint32_t cluster )
|
||||||
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF)) {
|
{
|
||||||
|
while ( ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_FREE ) && ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_EOF ) )
|
||||||
|
{
|
||||||
cluster = _FAT_fat_nextCluster( partition, cluster );
|
cluster = _FAT_fat_nextCluster( partition, cluster );
|
||||||
}
|
}
|
||||||
return cluster;
|
return cluster;
|
||||||
@ -368,12 +404,15 @@ uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
|
|||||||
_FAT_fat_freeClusterCount
|
_FAT_fat_freeClusterCount
|
||||||
Return the number of free clusters available
|
Return the number of free clusters available
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition) {
|
unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition )
|
||||||
|
{
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
uint32_t curCluster;
|
uint32_t curCluster;
|
||||||
|
|
||||||
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++) {
|
for ( curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++ )
|
||||||
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE) {
|
{
|
||||||
|
if ( _FAT_fat_nextCluster( partition, curCluster ) == CLUSTER_FREE )
|
||||||
|
{
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,13 +57,15 @@ uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster);
|
|||||||
|
|
||||||
unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition );
|
unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition );
|
||||||
|
|
||||||
static inline sec_t _FAT_fat_clusterToSector (PARTITION* partition, uint32_t cluster) {
|
static inline sec_t _FAT_fat_clusterToSector ( PARTITION* partition, uint32_t cluster )
|
||||||
|
{
|
||||||
return ( cluster >= CLUSTER_FIRST ) ?
|
return ( cluster >= CLUSTER_FIRST ) ?
|
||||||
( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart :
|
( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart :
|
||||||
partition->rootDirStart;
|
partition->rootDirStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _FAT_fat_isValidCluster (PARTITION* partition, uint32_t cluster) {
|
static inline bool _FAT_fat_isValidCluster ( PARTITION* partition, uint32_t cluster )
|
||||||
|
{
|
||||||
return ( cluster >= CLUSTER_FIRST ) && ( cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ );
|
return ( cluster >= CLUSTER_FIRST ) && ( cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,12 +40,14 @@
|
|||||||
#define MAX_DAY 31
|
#define MAX_DAY 31
|
||||||
#define MIN_DAY 1
|
#define MIN_DAY 1
|
||||||
|
|
||||||
uint16_t _FAT_filetime_getTimeFromRTC (void) {
|
uint16_t _FAT_filetime_getTimeFromRTC ( void )
|
||||||
|
{
|
||||||
#ifdef USE_RTC_TIME
|
#ifdef USE_RTC_TIME
|
||||||
struct tm timeParts;
|
struct tm timeParts;
|
||||||
time_t epochTime;
|
time_t epochTime;
|
||||||
|
|
||||||
if (time(&epochTime) == (time_t)-1) {
|
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
localtime_r( &epochTime, &timeParts );
|
localtime_r( &epochTime, &timeParts );
|
||||||
@ -67,12 +69,14 @@ uint16_t _FAT_filetime_getTimeFromRTC (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t _FAT_filetime_getDateFromRTC (void) {
|
uint16_t _FAT_filetime_getDateFromRTC ( void )
|
||||||
|
{
|
||||||
#ifdef USE_RTC_TIME
|
#ifdef USE_RTC_TIME
|
||||||
struct tm timeParts;
|
struct tm timeParts;
|
||||||
time_t epochTime;
|
time_t epochTime;
|
||||||
|
|
||||||
if (time(&epochTime) == (time_t)-1) {
|
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
localtime_r( &epochTime, &timeParts );
|
localtime_r( &epochTime, &timeParts );
|
||||||
@ -90,7 +94,8 @@ uint16_t _FAT_filetime_getDateFromRTC (void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d) {
|
time_t _FAT_filetime_to_time_t ( uint16_t t, uint16_t d )
|
||||||
|
{
|
||||||
struct tm timeParts;
|
struct tm timeParts;
|
||||||
|
|
||||||
timeParts.tm_hour = t >> 11;
|
timeParts.tm_hour = t >> 11;
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
#include "mem_allocate.h"
|
#include "mem_allocate.h"
|
||||||
#include "disc_fat.h"
|
#include "disc_fat.h"
|
||||||
|
|
||||||
static const devoptab_t dotab_fat = {
|
static const devoptab_t dotab_fat =
|
||||||
|
{
|
||||||
"fat",
|
"fat",
|
||||||
sizeof ( FILE_STRUCT ),
|
sizeof ( FILE_STRUCT ),
|
||||||
_FAT_open_r,
|
_FAT_open_r,
|
||||||
@ -64,7 +65,8 @@ static const devoptab_t dotab_fat = {
|
|||||||
NULL /* Device data */
|
NULL /* Device data */
|
||||||
};
|
};
|
||||||
|
|
||||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) {
|
bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage )
|
||||||
|
{
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
devoptab_t* devops;
|
devoptab_t* devops;
|
||||||
char* nameCopy;
|
char* nameCopy;
|
||||||
@ -72,13 +74,15 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
|||||||
if ( !interface->startup() )
|
if ( !interface->startup() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!interface->isInserted()) {
|
if ( !interface->isInserted() )
|
||||||
|
{
|
||||||
interface->shutdown();
|
interface->shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
devops = _FAT_mem_allocate ( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
devops = _FAT_mem_allocate ( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
||||||
if (!devops) {
|
if ( !devops )
|
||||||
|
{
|
||||||
interface->shutdown();
|
interface->shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -87,7 +91,8 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
|||||||
|
|
||||||
// Initialize the file system
|
// Initialize the file system
|
||||||
partition = _FAT_partition_constructor ( interface, cacheSize, SectorsPerPage, startSector );
|
partition = _FAT_partition_constructor ( interface, cacheSize, SectorsPerPage, startSector );
|
||||||
if (!partition) {
|
if ( !partition )
|
||||||
|
{
|
||||||
_FAT_mem_free ( devops );
|
_FAT_mem_free ( devops );
|
||||||
interface->shutdown();
|
interface->shutdown();
|
||||||
return false;
|
return false;
|
||||||
@ -104,26 +109,31 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) {
|
bool fatMountSimple ( const char* name, const DISC_INTERFACE* interface )
|
||||||
|
{
|
||||||
return fatMount ( name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE );
|
return fatMount ( name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE );
|
||||||
}
|
}
|
||||||
|
|
||||||
void fatUnmount (const char* name) {
|
void fatUnmount ( const char* name )
|
||||||
|
{
|
||||||
devoptab_t *devops;
|
devoptab_t *devops;
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
const DISC_INTERFACE *disc;
|
const DISC_INTERFACE *disc;
|
||||||
|
|
||||||
devops = ( devoptab_t* )GetDeviceOpTab ( name );
|
devops = ( devoptab_t* )GetDeviceOpTab ( name );
|
||||||
if (!devops) {
|
if ( !devops )
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
||||||
if (devops->open_r != dotab_fat.open_r) {
|
if ( devops->open_r != dotab_fat.open_r )
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RemoveDevice (name) == -1) {
|
if ( RemoveDevice ( name ) == -1 )
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +144,8 @@ void fatUnmount (const char* name) {
|
|||||||
disc->shutdown();
|
disc->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
int defaultDevice = -1;
|
int defaultDevice = -1;
|
||||||
const DISC_INTERFACE *disc;
|
const DISC_INTERFACE *disc;
|
||||||
@ -144,25 +155,30 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
|||||||
i++ )
|
i++ )
|
||||||
{
|
{
|
||||||
disc = _FAT_disc_interfaces[i].getInterface();
|
disc = _FAT_disc_interfaces[i].getInterface();
|
||||||
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) {
|
if ( fatMount ( _FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE ) )
|
||||||
|
{
|
||||||
// The first device to successfully mount is set as the default
|
// The first device to successfully mount is set as the default
|
||||||
if (defaultDevice < 0) {
|
if ( defaultDevice < 0 )
|
||||||
|
{
|
||||||
defaultDevice = i;
|
defaultDevice = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultDevice < 0) {
|
if ( defaultDevice < 0 )
|
||||||
|
{
|
||||||
// None of our devices mounted
|
// None of our devices mounted
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setAsDefaultDevice) {
|
if ( setAsDefaultDevice )
|
||||||
|
{
|
||||||
char filePath[MAXPATHLEN * 2];
|
char filePath[MAXPATHLEN * 2];
|
||||||
strcpy ( filePath, _FAT_disc_interfaces[defaultDevice].name );
|
strcpy ( filePath, _FAT_disc_interfaces[defaultDevice].name );
|
||||||
strcat ( filePath, ":/" );
|
strcat ( filePath, ":/" );
|
||||||
#ifdef ARGV_MAGIC
|
#ifdef ARGV_MAGIC
|
||||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL ) {
|
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' ) != NULL )
|
||||||
|
{
|
||||||
// Check the app's path against each of our mounted devices, to see
|
// Check the app's path against each of our mounted devices, to see
|
||||||
// if we can support it. If so, change to that path.
|
// if we can support it. If so, change to that path.
|
||||||
for ( i = 0;
|
for ( i = 0;
|
||||||
@ -176,7 +192,8 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
|||||||
strcpy( filePath, __system_argv->argv[0] );
|
strcpy( filePath, __system_argv->argv[0] );
|
||||||
lastSlash = strrchr( filePath, '/' );
|
lastSlash = strrchr( filePath, '/' );
|
||||||
|
|
||||||
if ( NULL != lastSlash) {
|
if ( NULL != lastSlash )
|
||||||
|
{
|
||||||
if ( *( lastSlash - 1 ) == ':' ) lastSlash++;
|
if ( *( lastSlash - 1 ) == ':' ) lastSlash++;
|
||||||
*lastSlash = 0;
|
*lastSlash = 0;
|
||||||
}
|
}
|
||||||
@ -190,7 +207,8 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fatInitDefault (void) {
|
bool fatInitDefault ( void )
|
||||||
|
{
|
||||||
return fatInit ( DEFAULT_CACHE_PAGES, true );
|
return fatInit ( DEFAULT_CACHE_PAGES, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,16 +33,19 @@
|
|||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
static inline void* _FAT_mem_allocate (size_t size) {
|
static inline void* _FAT_mem_allocate ( size_t size )
|
||||||
|
{
|
||||||
return malloc ( size );
|
return malloc ( size );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void* _FAT_mem_align (size_t size) {
|
static inline void* _FAT_mem_align ( size_t size )
|
||||||
|
{
|
||||||
|
|
||||||
return memalign ( 32, size );
|
return memalign ( 32, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _FAT_mem_free (void* mem) {
|
static inline void _FAT_mem_free ( void* mem )
|
||||||
|
{
|
||||||
free ( mem );
|
free ( mem );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,8 @@ Data offsets
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// BIOS Parameter Block offsets
|
// BIOS Parameter Block offsets
|
||||||
enum BPB {
|
enum BPB
|
||||||
|
{
|
||||||
BPB_jmpBoot = 0x00,
|
BPB_jmpBoot = 0x00,
|
||||||
BPB_OEMName = 0x03,
|
BPB_OEMName = 0x03,
|
||||||
// BIOS Parameter Block
|
// BIOS Parameter Block
|
||||||
@ -107,24 +108,28 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
|||||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||||
|
|
||||||
// Read first sector of disc
|
// Read first sector of disc
|
||||||
if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) {
|
if ( !_FAT_disc_readSectors ( disc, 0, 1, sectorBuffer ) )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy( part_table, sectorBuffer + 0x1BE, 16*4 );
|
memcpy( part_table, sectorBuffer + 0x1BE, 16*4 );
|
||||||
ptr = part_table;
|
ptr = part_table;
|
||||||
|
|
||||||
for(i=0;i<4;i++,ptr+=16) {
|
for ( i = 0; i < 4; i++, ptr += 16 )
|
||||||
|
{
|
||||||
sec_t part_lba = u8array_to_u32( ptr, 0x8 );
|
sec_t part_lba = u8array_to_u32( ptr, 0x8 );
|
||||||
|
|
||||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||||
|
{
|
||||||
return part_lba;
|
return part_lba;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ptr[4] == 0 ) continue;
|
if ( ptr[4] == 0 ) continue;
|
||||||
|
|
||||||
if(ptr[4]==0x0F) {
|
if ( ptr[4] == 0x0F )
|
||||||
|
{
|
||||||
sec_t part_lba2 = part_lba;
|
sec_t part_lba2 = part_lba;
|
||||||
sec_t next_lba2 = 0;
|
sec_t next_lba2 = 0;
|
||||||
int n;
|
int n;
|
||||||
@ -146,10 +151,13 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
|||||||
|
|
||||||
if ( next_lba2 == 0 ) break;
|
if ( next_lba2 == 0 ) break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( !_FAT_disc_readSectors ( disc, part_lba, 1, sectorBuffer ) ) return 0;
|
if ( !_FAT_disc_readSectors ( disc, part_lba, 1, sectorBuffer ) ) return 0;
|
||||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||||
|
{
|
||||||
return part_lba;
|
return part_lba;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,31 +165,42 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) {
|
PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector )
|
||||||
|
{
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||||
|
|
||||||
// Read first sector of disc
|
// Read first sector of disc
|
||||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
|
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure it is a valid MBR or boot sector
|
// Make sure it is a valid MBR or boot sector
|
||||||
if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) {
|
if ( ( sectorBuffer[BPB_bootSig_55] != 0x55 ) || ( sectorBuffer[BPB_bootSig_AA] != 0xAA ) )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startSector != 0) {
|
if ( startSector != 0 )
|
||||||
|
{
|
||||||
// We're told where to start the partition, so just accept it
|
// We're told where to start the partition, so just accept it
|
||||||
} else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
}
|
||||||
|
else if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||||
|
{
|
||||||
// Check if there is a FAT string, which indicates this is a boot sector
|
// Check if there is a FAT string, which indicates this is a boot sector
|
||||||
startSector = 0;
|
startSector = 0;
|
||||||
} else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
}
|
||||||
|
else if ( !memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||||
|
{
|
||||||
// Check for FAT32
|
// Check for FAT32
|
||||||
startSector = 0;
|
startSector = 0;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
startSector = FindFirstValidPartition( disc );
|
startSector = FindFirstValidPartition( disc );
|
||||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
|
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,7 +220,8 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
|||||||
}
|
}
|
||||||
|
|
||||||
partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) );
|
partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) );
|
||||||
if (partition == NULL) {
|
if ( partition == NULL )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,12 +235,14 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
|||||||
|
|
||||||
// Store required information about the file system
|
// Store required information about the file system
|
||||||
partition->fat.sectorsPerFat = u8array_to_u16( sectorBuffer, BPB_sectorsPerFAT );
|
partition->fat.sectorsPerFat = u8array_to_u16( sectorBuffer, BPB_sectorsPerFAT );
|
||||||
if (partition->fat.sectorsPerFat == 0) {
|
if ( partition->fat.sectorsPerFat == 0 )
|
||||||
|
{
|
||||||
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32 );
|
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32 );
|
||||||
}
|
}
|
||||||
|
|
||||||
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall );
|
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall );
|
||||||
if (partition->numberOfSectors == 0) {
|
if ( partition->numberOfSectors == 0 )
|
||||||
|
{
|
||||||
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors );
|
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,21 +262,30 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
|||||||
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
||||||
partition->fat.firstFree = CLUSTER_FIRST;
|
partition->fat.firstFree = CLUSTER_FIRST;
|
||||||
|
|
||||||
if (clusterCount < CLUSTERS_PER_FAT12) {
|
if ( clusterCount < CLUSTERS_PER_FAT12 )
|
||||||
|
{
|
||||||
partition->filesysType = FS_FAT12; // FAT12 volume
|
partition->filesysType = FS_FAT12; // FAT12 volume
|
||||||
} else if (clusterCount < CLUSTERS_PER_FAT16) {
|
}
|
||||||
|
else if ( clusterCount < CLUSTERS_PER_FAT16 )
|
||||||
|
{
|
||||||
partition->filesysType = FS_FAT16; // FAT16 volume
|
partition->filesysType = FS_FAT16; // FAT16 volume
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
partition->filesysType = FS_FAT32; // FAT32 volume
|
partition->filesysType = FS_FAT32; // FAT32 volume
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partition->filesysType != FS_FAT32) {
|
if ( partition->filesysType != FS_FAT32 )
|
||||||
|
{
|
||||||
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Set up for the FAT32 way
|
// Set up for the FAT32 way
|
||||||
partition->rootDirCluster = u8array_to_u32( sectorBuffer, BPB_FAT32_rootClus );
|
partition->rootDirCluster = u8array_to_u32( sectorBuffer, BPB_FAT32_rootClus );
|
||||||
// Check if FAT mirroring is enabled
|
// Check if FAT mirroring is enabled
|
||||||
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) {
|
if ( !( sectorBuffer[BPB_FAT32_extFlags] & 0x80 ) )
|
||||||
|
{
|
||||||
// Use the active FAT
|
// Use the active FAT
|
||||||
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * ( sectorBuffer[BPB_FAT32_extFlags] & 0x0F ) );
|
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * ( sectorBuffer[BPB_FAT32_extFlags] & 0x0F ) );
|
||||||
}
|
}
|
||||||
@ -276,14 +307,16 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
|||||||
return partition;
|
return partition;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _FAT_partition_destructor (PARTITION* partition) {
|
void _FAT_partition_destructor ( PARTITION* partition )
|
||||||
|
{
|
||||||
FILE_STRUCT* nextFile;
|
FILE_STRUCT* nextFile;
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock( &partition->lock );
|
||||||
|
|
||||||
// Synchronize open files
|
// Synchronize open files
|
||||||
nextFile = partition->firstOpenFile;
|
nextFile = partition->firstOpenFile;
|
||||||
while (nextFile) {
|
while ( nextFile )
|
||||||
|
{
|
||||||
_FAT_syncToDisc ( nextFile );
|
_FAT_syncToDisc ( nextFile );
|
||||||
nextFile = nextFile->nextOpenFile;
|
nextFile = nextFile->nextOpenFile;
|
||||||
}
|
}
|
||||||
@ -299,12 +332,14 @@ void _FAT_partition_destructor (PARTITION* partition) {
|
|||||||
_FAT_mem_free ( partition );
|
_FAT_mem_free ( partition );
|
||||||
}
|
}
|
||||||
|
|
||||||
PARTITION* _FAT_partition_getPartitionFromPath (const char* path) {
|
PARTITION* _FAT_partition_getPartitionFromPath ( const char* path )
|
||||||
|
{
|
||||||
const devoptab_t *devops;
|
const devoptab_t *devops;
|
||||||
|
|
||||||
devops = GetDeviceOpTab ( path );
|
devops = GetDeviceOpTab ( path );
|
||||||
|
|
||||||
if (!devops) {
|
if ( !devops )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,14 +40,16 @@ extern const char* DEVICE_NAME;
|
|||||||
// Filesystem type
|
// Filesystem type
|
||||||
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
sec_t fatStart;
|
sec_t fatStart;
|
||||||
uint32_t sectorsPerFat;
|
uint32_t sectorsPerFat;
|
||||||
uint32_t lastCluster;
|
uint32_t lastCluster;
|
||||||
uint32_t firstFree;
|
uint32_t firstFree;
|
||||||
} FAT;
|
} FAT;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const DISC_INTERFACE* disc;
|
const DISC_INTERFACE* disc;
|
||||||
CACHE* cache;
|
CACHE* cache;
|
||||||
// Info about the partition
|
// Info about the partition
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -122,7 +122,8 @@ typedef char BIGSID[40];
|
|||||||
* (private to this module)
|
* (private to this module)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct MAPLIST {
|
struct MAPLIST
|
||||||
|
{
|
||||||
struct MAPLIST *next;
|
struct MAPLIST *next;
|
||||||
char *uidstr; /* uid text from the same record */
|
char *uidstr; /* uid text from the same record */
|
||||||
char *gidstr; /* gid text from the same record */
|
char *gidstr; /* gid text from the same record */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -49,7 +49,8 @@ extern ntfschar TXF_DATA[10];
|
|||||||
*
|
*
|
||||||
* TODO: Describe them.
|
* TODO: Describe them.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||||
LCN_RL_NOT_MAPPED = -2,
|
LCN_RL_NOT_MAPPED = -2,
|
||||||
LCN_ENOENT = -3,
|
LCN_ENOENT = -3,
|
||||||
@ -75,7 +76,8 @@ typedef enum {
|
|||||||
* any modification of the search context, to automagically get the next
|
* any modification of the search context, to automagically get the next
|
||||||
* matching attribute.
|
* matching attribute.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_attr_search_ctx {
|
struct _ntfs_attr_search_ctx
|
||||||
|
{
|
||||||
MFT_RECORD *mrec;
|
MFT_RECORD *mrec;
|
||||||
ATTR_RECORD *attr;
|
ATTR_RECORD *attr;
|
||||||
BOOL is_first;
|
BOOL is_first;
|
||||||
@ -174,7 +176,8 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
|
|||||||
* @state contains NTFS attribute specific flags describing this attribute
|
* @state contains NTFS attribute specific flags describing this attribute
|
||||||
* structure. See ntfs_attr_state_bits above.
|
* structure. See ntfs_attr_state_bits above.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_attr {
|
struct _ntfs_attr
|
||||||
|
{
|
||||||
runlist_element *rl;
|
runlist_element *rl;
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
ATTR_TYPES type;
|
ATTR_TYPES type;
|
||||||
@ -196,7 +199,8 @@ struct _ntfs_attr {
|
|||||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
||||||
* structure
|
* structure
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NA_Initialized, /* 1: structure is initialized. */
|
NA_Initialized, /* 1: structure is initialized. */
|
||||||
NA_NonResident, /* 1: Attribute is not resident. */
|
NA_NonResident, /* 1: Attribute is not resident. */
|
||||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||||
@ -243,7 +247,8 @@ GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
|||||||
*
|
*
|
||||||
* For convenience. Used in the attr structure.
|
* For convenience. Used in the attr structure.
|
||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union
|
||||||
|
{
|
||||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||||
a_val without specifying any of the below. */
|
a_val without specifying any of the below. */
|
||||||
STANDARD_INFORMATION std_inf;
|
STANDARD_INFORMATION std_inf;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -62,7 +62,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
|||||||
{
|
{
|
||||||
ATTR_LIST_ENTRY *ale;
|
ATTR_LIST_ENTRY *ale;
|
||||||
|
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Invalid arguments.\n" );
|
ntfs_log_trace( "Invalid arguments.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -70,13 +71,15 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
|
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
|
||||||
|
|
||||||
if (!NInoAttrList(ni)) {
|
if ( !NInoAttrList( ni ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Inode haven't got attribute list.\n" );
|
ntfs_log_trace( "Inode haven't got attribute list.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ni->attr_list) {
|
if ( !ni->attr_list )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -84,7 +87,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
|||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
|
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
|
||||||
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
|
||||||
|
{
|
||||||
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
|
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
|
||||||
return 1;
|
return 1;
|
||||||
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
|
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
|
||||||
@ -117,7 +121,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
( long long ) ni->mft_no,
|
( long long ) ni->mft_no,
|
||||||
( unsigned ) le32_to_cpu( attr->type ) );
|
( unsigned ) le32_to_cpu( attr->type ) );
|
||||||
|
|
||||||
if (!ni || !attr) {
|
if ( !ni || !attr )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Invalid arguments.\n" );
|
ntfs_log_trace( "Invalid arguments.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -128,7 +133,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
if ( ni->nr_extents == -1 )
|
if ( ni->nr_extents == -1 )
|
||||||
ni = ni->base_ni;
|
ni = ni->base_ni;
|
||||||
|
|
||||||
if (!NInoAttrList(ni)) {
|
if ( !NInoAttrList( ni ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
ntfs_log_trace( "Attribute list isn't present.\n" );
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -143,7 +149,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
|
|
||||||
/* Find place for the new entry. */
|
/* Find place for the new entry. */
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||||
if (!ctx) {
|
if ( !ctx )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -153,9 +160,11 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
( attr->non_resident ) ? le64_to_cpu( attr->lowest_vcn ) :
|
( attr->non_resident ) ? le64_to_cpu( attr->lowest_vcn ) :
|
||||||
0, ( attr->non_resident ) ? NULL : ( ( u8* )attr +
|
0, ( attr->non_resident ) ? NULL : ( ( u8* )attr +
|
||||||
le16_to_cpu( attr->value_offset ) ), ( attr->non_resident ) ?
|
le16_to_cpu( attr->value_offset ) ), ( attr->non_resident ) ?
|
||||||
0 : le32_to_cpu(attr->value_length), ctx)) {
|
0 : le32_to_cpu( attr->value_length ), ctx ) )
|
||||||
|
{
|
||||||
/* Found some extent, check it to be before new extent. */
|
/* Found some extent, check it to be before new extent. */
|
||||||
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) {
|
if ( ctx->al_entry->lowest_vcn == attr->lowest_vcn )
|
||||||
|
{
|
||||||
err = EEXIST;
|
err = EEXIST;
|
||||||
ntfs_log_trace( "Such attribute already present in the "
|
ntfs_log_trace( "Such attribute already present in the "
|
||||||
"attribute list.\n" );
|
"attribute list.\n" );
|
||||||
@ -165,9 +174,12 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
/* Add new entry after this extent. */
|
/* Add new entry after this extent. */
|
||||||
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
|
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
|
||||||
le16_to_cpu( ctx->al_entry->length ) );
|
le16_to_cpu( ctx->al_entry->length ) );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Check for real errors. */
|
/* Check for real errors. */
|
||||||
if (errno != ENOENT) {
|
if ( errno != ENOENT )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "Attribute lookup failed.\n" );
|
ntfs_log_trace( "Attribute lookup failed.\n" );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
@ -201,12 +213,14 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
|
|
||||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
|
if ( ntfs_attr_truncate( na, ni->attr_list_size + entry_len ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -250,7 +264,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
ATTR_LIST_ENTRY *ale;
|
ATTR_LIST_ENTRY *ale;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
if ( !ctx || !ctx->ntfs_ino || !ctx->al_entry )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Invalid arguments.\n" );
|
ntfs_log_trace( "Invalid arguments.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -267,7 +282,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
( unsigned ) le32_to_cpu( ctx->al_entry->type ),
|
( unsigned ) le32_to_cpu( ctx->al_entry->type ),
|
||||||
( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) );
|
( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) );
|
||||||
|
|
||||||
if (!NInoAttrList(base_ni)) {
|
if ( !NInoAttrList( base_ni ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
ntfs_log_trace( "Attribute list isn't present.\n" );
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -281,12 +297,14 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
|
|
||||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||||
na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (ntfs_attr_truncate(na, new_al_len)) {
|
if ( ntfs_attr_truncate( na, new_al_len ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
@ -34,20 +34,24 @@
|
|||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
Functions to deal with little endian values stored in uint8_t arrays
|
Functions to deal with little endian values stored in uint8_t arrays
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
|
||||||
|
{
|
||||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
||||||
|
{
|
||||||
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
|
||||||
|
{
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset] = ( uint8_t ) value;
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
||||||
|
{
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset] = ( uint8_t ) value;
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
item[offset + 2] = ( uint8_t )( value >> 16 );
|
||||||
|
@ -119,7 +119,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
u8 *buf, *lastbyte_buf;
|
u8 *buf, *lastbyte_buf;
|
||||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
||||||
|
|
||||||
if (!na || start_bit < 0 || count < 0) {
|
if ( !na || start_bit < 0 || count < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)",
|
ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)",
|
||||||
__FUNCTION__, na, ( long long )start_bit, ( long long )count );
|
__FUNCTION__, na, ( long long )start_bit, ( long long )count );
|
||||||
@ -145,16 +146,19 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
memset( buf, value ? 0xff : 0, bufsize );
|
memset( buf, value ? 0xff : 0, bufsize );
|
||||||
|
|
||||||
/* If there is a first partial byte... */
|
/* If there is a first partial byte... */
|
||||||
if (bit) {
|
if ( bit )
|
||||||
|
{
|
||||||
/* read it in... */
|
/* read it in... */
|
||||||
br = ntfs_attr_pread( na, start_bit >> 3, 1, buf );
|
br = ntfs_attr_pread( na, start_bit >> 3, 1, buf );
|
||||||
if (br != 1) {
|
if ( br != 1 )
|
||||||
|
{
|
||||||
if ( br >= 0 )
|
if ( br >= 0 )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and set or clear the appropriate bits in it. */
|
/* and set or clear the appropriate bits in it. */
|
||||||
while ((bit & 7) && count--) {
|
while ( ( bit & 7 ) && count-- )
|
||||||
|
{
|
||||||
if ( value )
|
if ( value )
|
||||||
*buf |= 1 << bit++;
|
*buf |= 1 << bit++;
|
||||||
else
|
else
|
||||||
@ -168,11 +172,14 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
lastbyte = 0;
|
lastbyte = 0;
|
||||||
lastbyte_buf = NULL;
|
lastbyte_buf = NULL;
|
||||||
bit = count & 7;
|
bit = count & 7;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
/* If there is a last partial byte... */
|
/* If there is a last partial byte... */
|
||||||
if (count > 0 && bit) {
|
if ( count > 0 && bit )
|
||||||
|
{
|
||||||
lastbyte_pos = ( ( count + 7 ) >> 3 ) + firstbyte;
|
lastbyte_pos = ( ( count + 7 ) >> 3 ) + firstbyte;
|
||||||
if (!lastbyte_pos) {
|
if ( !lastbyte_pos )
|
||||||
|
{
|
||||||
// FIXME: Eeek! BUG!
|
// FIXME: Eeek! BUG!
|
||||||
ntfs_log_error( "Lastbyte is zero. Leaving "
|
ntfs_log_error( "Lastbyte is zero. Leaving "
|
||||||
"inconsistent metadata.\n" );
|
"inconsistent metadata.\n" );
|
||||||
@ -180,13 +187,15 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and it is in the currently loaded bitmap window... */
|
/* and it is in the currently loaded bitmap window... */
|
||||||
if (lastbyte_pos <= bufsize) {
|
if ( lastbyte_pos <= bufsize )
|
||||||
|
{
|
||||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||||
|
|
||||||
/* read the byte in... */
|
/* read the byte in... */
|
||||||
br = ntfs_attr_pread( na, ( start_bit + count ) >>
|
br = ntfs_attr_pread( na, ( start_bit + count ) >>
|
||||||
3, 1, lastbyte_buf );
|
3, 1, lastbyte_buf );
|
||||||
if (br != 1) {
|
if ( br != 1 )
|
||||||
|
{
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
if ( br >= 0 )
|
if ( br >= 0 )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -196,7 +205,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and set/clear the appropriate bits in it. */
|
/* and set/clear the appropriate bits in it. */
|
||||||
while (bit && count--) {
|
while ( bit && count-- )
|
||||||
|
{
|
||||||
if ( value )
|
if ( value )
|
||||||
*lastbyte_buf |= 1 << --bit;
|
*lastbyte_buf |= 1 << --bit;
|
||||||
else
|
else
|
||||||
@ -212,7 +222,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
/* Write the prepared buffer to disk. */
|
/* Write the prepared buffer to disk. */
|
||||||
tmp = ( start_bit >> 3 ) - firstbyte;
|
tmp = ( start_bit >> 3 ) - firstbyte;
|
||||||
br = ntfs_attr_pwrite( na, tmp, bufsize, buf );
|
br = ntfs_attr_pwrite( na, tmp, bufsize, buf );
|
||||||
if (br != bufsize) {
|
if ( br != bufsize )
|
||||||
|
{
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
if ( br >= 0 )
|
if ( br >= 0 )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -224,7 +235,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
|
|
||||||
/* Update counters. */
|
/* Update counters. */
|
||||||
tmp = ( bufsize - firstbyte - lastbyte ) << 3;
|
tmp = ( bufsize - firstbyte - lastbyte ) << 3;
|
||||||
if (firstbyte) {
|
if ( firstbyte )
|
||||||
|
{
|
||||||
firstbyte = 0;
|
firstbyte = 0;
|
||||||
/*
|
/*
|
||||||
* Re-set the partial first byte so a subsequent write
|
* Re-set the partial first byte so a subsequent write
|
||||||
@ -237,7 +249,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) )
|
if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) )
|
||||||
bufsize = tmp;
|
bufsize = tmp;
|
||||||
|
|
||||||
if (lastbyte && count != 0) {
|
if ( lastbyte && count != 0 )
|
||||||
|
{
|
||||||
// FIXME: Eeek! BUG!
|
// FIXME: Eeek! BUG!
|
||||||
ntfs_log_error( "Last buffer but count is not zero "
|
ntfs_log_error( "Last buffer but count is not zero "
|
||||||
"(%lld). Leaving inconsistent metadata.\n",
|
"(%lld). Leaving inconsistent metadata.\n",
|
||||||
@ -245,7 +258,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
errno = EIO;
|
errno = EIO;
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
} while (count > 0);
|
}
|
||||||
|
while ( count > 0 );
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
@ -65,21 +65,24 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
ntfs_log_debug( "Beginning bootsector check.\n" );
|
ntfs_log_debug( "Beginning bootsector check.\n" );
|
||||||
|
|
||||||
ntfs_log_debug( "Checking OEMid, NTFS signature.\n" );
|
ntfs_log_debug( "Checking OEMid, NTFS signature.\n" );
|
||||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
if ( b->oem_id != cpu_to_le64( 0x202020205346544eULL ) ) /* "NTFS " */
|
||||||
|
{
|
||||||
ntfs_log_error( "NTFS signature is missing.\n" );
|
ntfs_log_error( "NTFS signature is missing.\n" );
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking bytes per sector.\n" );
|
ntfs_log_debug( "Checking bytes per sector.\n" );
|
||||||
if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 ||
|
if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 ||
|
||||||
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
|
le16_to_cpu( b->bpb.bytes_per_sector ) > 4096 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Unexpected bytes per sector value (%d).\n",
|
ntfs_log_error( "Unexpected bytes per sector value (%d).\n",
|
||||||
le16_to_cpu( b->bpb.bytes_per_sector ) );
|
le16_to_cpu( b->bpb.bytes_per_sector ) );
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking sectors per cluster.\n" );
|
ntfs_log_debug( "Checking sectors per cluster.\n" );
|
||||||
switch (b->bpb.sectors_per_cluster) {
|
switch ( b->bpb.sectors_per_cluster )
|
||||||
|
{
|
||||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -91,7 +94,8 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
ntfs_log_debug( "Checking cluster size.\n" );
|
ntfs_log_debug( "Checking cluster size.\n" );
|
||||||
i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) *
|
i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) *
|
||||||
b->bpb.sectors_per_cluster;
|
b->bpb.sectors_per_cluster;
|
||||||
if (i > 65536) {
|
if ( i > 65536 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Unexpected cluster size (%d).\n", i );
|
ntfs_log_error( "Unexpected cluster size (%d).\n", i );
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
@ -102,7 +106,8 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
le16_to_cpu( b->bpb.sectors ) ||
|
le16_to_cpu( b->bpb.sectors ) ||
|
||||||
le16_to_cpu( b->bpb.sectors_per_fat ) ||
|
le16_to_cpu( b->bpb.sectors_per_fat ) ||
|
||||||
le32_to_cpu( b->bpb.large_sectors ) ||
|
le32_to_cpu( b->bpb.large_sectors ) ||
|
||||||
b->bpb.fats) {
|
b->bpb.fats )
|
||||||
|
{
|
||||||
ntfs_log_error( "Reserved fields aren't zero "
|
ntfs_log_error( "Reserved fields aren't zero "
|
||||||
"(%d, %d, %d, %d, %d, %d).\n",
|
"(%d, %d, %d, %d, %d, %d).\n",
|
||||||
le16_to_cpu( b->bpb.reserved_sectors ),
|
le16_to_cpu( b->bpb.reserved_sectors ),
|
||||||
@ -116,8 +121,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
|
|
||||||
ntfs_log_debug( "Checking clusters per mft record.\n" );
|
ntfs_log_debug( "Checking clusters per mft record.\n" );
|
||||||
if ( ( u8 )b->clusters_per_mft_record < 0xe1 ||
|
if ( ( u8 )b->clusters_per_mft_record < 0xe1 ||
|
||||||
(u8)b->clusters_per_mft_record > 0xf7) {
|
( u8 )b->clusters_per_mft_record > 0xf7 )
|
||||||
switch (b->clusters_per_mft_record) {
|
{
|
||||||
|
switch ( b->clusters_per_mft_record )
|
||||||
|
{
|
||||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -129,8 +136,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
|
|
||||||
ntfs_log_debug( "Checking clusters per index block.\n" );
|
ntfs_log_debug( "Checking clusters per index block.\n" );
|
||||||
if ( ( u8 )b->clusters_per_index_record < 0xe1 ||
|
if ( ( u8 )b->clusters_per_index_record < 0xe1 ||
|
||||||
(u8)b->clusters_per_index_record > 0xf7) {
|
( u8 )b->clusters_per_index_record > 0xf7 )
|
||||||
switch (b->clusters_per_index_record) {
|
{
|
||||||
|
switch ( b->clusters_per_index_record )
|
||||||
|
{
|
||||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -188,7 +197,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
*/
|
*/
|
||||||
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
||||||
ntfs_log_debug( "SectorsPerCluster = 0x%x\n", sectors_per_cluster );
|
ntfs_log_debug( "SectorsPerCluster = 0x%x\n", sectors_per_cluster );
|
||||||
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
|
if ( sectors_per_cluster & ( sectors_per_cluster - 1 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2."
|
ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2."
|
||||||
"\n", sectors_per_cluster );
|
"\n", sectors_per_cluster );
|
||||||
return -1;
|
return -1;
|
||||||
@ -196,13 +206,15 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
|
|
||||||
sectors = sle64_to_cpu( bs->number_of_sectors );
|
sectors = sle64_to_cpu( bs->number_of_sectors );
|
||||||
ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors );
|
ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors );
|
||||||
if (!sectors) {
|
if ( !sectors )
|
||||||
|
{
|
||||||
ntfs_log_error( "Volume size is set to zero.\n" );
|
ntfs_log_error( "Volume size is set to zero.\n" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( vol->dev->d_ops->seek( vol->dev,
|
if ( vol->dev->d_ops->seek( vol->dev,
|
||||||
( sectors - 1 ) << vol->sector_size_bits,
|
( sectors - 1 ) << vol->sector_size_bits,
|
||||||
SEEK_SET) == -1) {
|
SEEK_SET ) == -1 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to read last sector (%lld)",
|
ntfs_log_perror( "Failed to read last sector (%lld)",
|
||||||
( long long )sectors );
|
( long long )sectors );
|
||||||
ntfs_log_error( "%s", last_sector_error );
|
ntfs_log_error( "%s", last_sector_error );
|
||||||
@ -216,7 +228,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
ntfs_log_debug( "MFT LCN = %lld\n", ( long long )vol->mft_lcn );
|
ntfs_log_debug( "MFT LCN = %lld\n", ( long long )vol->mft_lcn );
|
||||||
ntfs_log_debug( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn );
|
ntfs_log_debug( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn );
|
||||||
if ( vol->mft_lcn > vol->nr_clusters ||
|
if ( vol->mft_lcn > vol->nr_clusters ||
|
||||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
vol->mftmirr_lcn > vol->nr_clusters )
|
||||||
|
{
|
||||||
ntfs_log_error( "$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
ntfs_log_error( "$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||||
"greater than the number of clusters (%lld).\n",
|
"greater than the number of clusters (%lld).\n",
|
||||||
( long long )vol->mft_lcn, ( long long )vol->mftmirr_lcn,
|
( long long )vol->mft_lcn, ( long long )vol->mftmirr_lcn,
|
||||||
@ -225,7 +238,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||||
if (vol->cluster_size & (vol->cluster_size - 1)) {
|
if ( vol->cluster_size & ( vol->cluster_size - 1 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "cluster_size (%d) is not a power of 2.\n",
|
ntfs_log_error( "cluster_size (%d) is not a power of 2.\n",
|
||||||
vol->cluster_size );
|
vol->cluster_size );
|
||||||
return -1;
|
return -1;
|
||||||
@ -250,7 +264,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
vol->mft_record_size = 1 << -c;
|
vol->mft_record_size = 1 << -c;
|
||||||
else
|
else
|
||||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
vol->mft_record_size = c << vol->cluster_size_bits;
|
||||||
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
|
if ( vol->mft_record_size & ( vol->mft_record_size - 1 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "mft_record_size (%d) is not a power of 2.\n",
|
ntfs_log_error( "mft_record_size (%d) is not a power of 2.\n",
|
||||||
vol->mft_record_size );
|
vol->mft_record_size );
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -67,12 +67,15 @@ static void inserthashindex(struct CACHE_HEADER *cache,
|
|||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
struct HASH_ENTRY *first;
|
struct HASH_ENTRY *first;
|
||||||
|
|
||||||
if (cache->dohash) {
|
if ( cache->dohash )
|
||||||
|
{
|
||||||
h = cache->dohash( current );
|
h = cache->dohash( current );
|
||||||
if ((h >= 0) && (h < cache->max_hash)) {
|
if ( ( h >= 0 ) && ( h < cache->max_hash ) )
|
||||||
|
{
|
||||||
/* get a free link and insert at top of hash list */
|
/* get a free link and insert at top of hash list */
|
||||||
link = cache->free_hash;
|
link = cache->free_hash;
|
||||||
if (link) {
|
if ( link )
|
||||||
|
{
|
||||||
cache->free_hash = link->next;
|
cache->free_hash = link->next;
|
||||||
first = cache->first_hash[h];
|
first = cache->first_hash[h];
|
||||||
if ( first )
|
if ( first )
|
||||||
@ -81,13 +84,17 @@ static void inserthashindex(struct CACHE_HEADER *cache,
|
|||||||
link->next = NULL;
|
link->next = NULL;
|
||||||
link->entry = current;
|
link->entry = current;
|
||||||
cache->first_hash[h] = link;
|
cache->first_hash[h] = link;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "No more hash entries,"
|
ntfs_log_error( "No more hash entries,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name );
|
||||||
cache->dohash = ( cache_hash )NULL;
|
cache->dohash = ( cache_hash )NULL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "Illegal hash value,"
|
ntfs_log_error( "Illegal hash value,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name );
|
||||||
@ -106,29 +113,37 @@ static void drophashindex(struct CACHE_HEADER *cache,
|
|||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
struct HASH_ENTRY *previous;
|
struct HASH_ENTRY *previous;
|
||||||
|
|
||||||
if (cache->dohash) {
|
if ( cache->dohash )
|
||||||
if ((hash >= 0) && (hash < cache->max_hash)) {
|
{
|
||||||
|
if ( ( hash >= 0 ) && ( hash < cache->max_hash ) )
|
||||||
|
{
|
||||||
/* find the link and unlink */
|
/* find the link and unlink */
|
||||||
link = cache->first_hash[hash];
|
link = cache->first_hash[hash];
|
||||||
previous = ( struct HASH_ENTRY* )NULL;
|
previous = ( struct HASH_ENTRY* )NULL;
|
||||||
while (link && (link->entry != current)) {
|
while ( link && ( link->entry != current ) )
|
||||||
|
{
|
||||||
previous = link;
|
previous = link;
|
||||||
link = link->next;
|
link = link->next;
|
||||||
}
|
}
|
||||||
if (link) {
|
if ( link )
|
||||||
|
{
|
||||||
if ( previous )
|
if ( previous )
|
||||||
previous->next = link->next;
|
previous->next = link->next;
|
||||||
else
|
else
|
||||||
cache->first_hash[hash] = link->next;
|
cache->first_hash[hash] = link->next;
|
||||||
link->next = cache->free_hash;
|
link->next = cache->free_hash;
|
||||||
cache->free_hash = link;
|
cache->free_hash = link;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "Bad hash list,"
|
ntfs_log_error( "Bad hash list,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name );
|
||||||
cache->dohash = ( cache_hash )NULL;
|
cache->dohash = ( cache_hash )NULL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "Illegal hash value,"
|
ntfs_log_error( "Illegal hash value,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name );
|
||||||
@ -153,8 +168,10 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
|||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = ( struct CACHED_GENERIC* )NULL;
|
||||||
if (cache) {
|
if ( cache )
|
||||||
if (cache->dohash) {
|
{
|
||||||
|
if ( cache->dohash )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* locate the entry if present
|
* locate the entry if present
|
||||||
@ -166,21 +183,25 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
|||||||
if ( link )
|
if ( link )
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
}
|
}
|
||||||
if (!cache->dohash) {
|
if ( !cache->dohash )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list if no hash table
|
* Search sequentially in LRU list if no hash table
|
||||||
* or if hashing has just failed
|
* or if hashing has just failed
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
while ( current
|
while ( current
|
||||||
&& compare(current, wanted)) {
|
&& compare( current, wanted ) )
|
||||||
|
{
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (current) {
|
if ( current )
|
||||||
|
{
|
||||||
previous = current->previous;
|
previous = current->previous;
|
||||||
cache->hits++;
|
cache->hits++;
|
||||||
if (previous) {
|
if ( previous )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* found and not at head of list, unlink from current
|
* found and not at head of list, unlink from current
|
||||||
* position and relink as head of list
|
* position and relink as head of list
|
||||||
@ -219,8 +240,10 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = ( struct CACHED_GENERIC* )NULL;
|
||||||
if (cache) {
|
if ( cache )
|
||||||
if (cache->dohash) {
|
{
|
||||||
|
if ( cache->dohash )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* find out whether the entry if present
|
* find out whether the entry if present
|
||||||
@ -229,11 +252,13 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while ( link && compare( link->entry, item ) )
|
while ( link && compare( link->entry, item ) )
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if (link) {
|
if ( link )
|
||||||
|
{
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cache->dohash) {
|
if ( !cache->dohash )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list to locate the end,
|
* Search sequentially in LRU list to locate the end,
|
||||||
* and find out whether the entry is already in list
|
* and find out whether the entry is already in list
|
||||||
@ -242,12 +267,14 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
while ( current
|
while ( current
|
||||||
&& compare(current, item)) {
|
&& compare( current, item ) )
|
||||||
|
{
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current) {
|
if ( !current )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Not in list, get a free entry or reuse the
|
* Not in list, get a free entry or reuse the
|
||||||
* last entry, and relink as head of list
|
* last entry, and relink as head of list
|
||||||
@ -256,18 +283,23 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
* an entry is reused.
|
* an entry is reused.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (cache->free_entry) {
|
if ( cache->free_entry )
|
||||||
|
{
|
||||||
current = cache->free_entry;
|
current = cache->free_entry;
|
||||||
cache->free_entry = cache->free_entry->next;
|
cache->free_entry = cache->free_entry->next;
|
||||||
if (item->varsize) {
|
if ( item->varsize )
|
||||||
|
{
|
||||||
current->variable = ntfs_malloc(
|
current->variable = ntfs_malloc(
|
||||||
item->varsize );
|
item->varsize );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
current->variable = ( void* )NULL;
|
current->variable = ( void* )NULL;
|
||||||
current->varsize = item->varsize;
|
current->varsize = item->varsize;
|
||||||
if ( !cache->oldest_entry )
|
if ( !cache->oldest_entry )
|
||||||
cache->oldest_entry = current;
|
cache->oldest_entry = current;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* reusing the oldest entry */
|
/* reusing the oldest entry */
|
||||||
current = cache->oldest_entry;
|
current = cache->oldest_entry;
|
||||||
before = current->previous;
|
before = current->previous;
|
||||||
@ -278,7 +310,8 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
if ( cache->dofree )
|
if ( cache->dofree )
|
||||||
cache->dofree( current );
|
cache->dofree( current );
|
||||||
cache->oldest_entry = current->previous;
|
cache->oldest_entry = current->previous;
|
||||||
if (item->varsize) {
|
if ( item->varsize )
|
||||||
|
{
|
||||||
if ( current->varsize )
|
if ( current->varsize )
|
||||||
current->variable = realloc(
|
current->variable = realloc(
|
||||||
current->variable,
|
current->variable,
|
||||||
@ -286,7 +319,9 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
else
|
else
|
||||||
current->variable = ntfs_malloc(
|
current->variable = ntfs_malloc(
|
||||||
item->varsize );
|
item->varsize );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( current->varsize )
|
if ( current->varsize )
|
||||||
free( current->variable );
|
free( current->variable );
|
||||||
current->variable = ( void* )NULL;
|
current->variable = ( void* )NULL;
|
||||||
@ -299,11 +334,15 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
cache->most_recent_entry->previous = current;
|
cache->most_recent_entry->previous = current;
|
||||||
cache->most_recent_entry = current;
|
cache->most_recent_entry = current;
|
||||||
memcpy( current->fixed, item->fixed, cache->fixed_size );
|
memcpy( current->fixed, item->fixed, cache->fixed_size );
|
||||||
if (item->varsize) {
|
if ( item->varsize )
|
||||||
if (current->variable) {
|
{
|
||||||
|
if ( current->variable )
|
||||||
|
{
|
||||||
memcpy( current->variable,
|
memcpy( current->variable,
|
||||||
item->variable, item->varsize );
|
item->variable, item->varsize );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* no more memory for variable part
|
* no more memory for variable part
|
||||||
* recycle entry in free list
|
* recycle entry in free list
|
||||||
@ -314,7 +353,9 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
cache->free_entry = current;
|
cache->free_entry = current;
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = ( struct CACHED_GENERIC* )NULL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
current->variable = ( void* )NULL;
|
current->variable = ( void* )NULL;
|
||||||
current->varsize = 0;
|
current->varsize = 0;
|
||||||
}
|
}
|
||||||
@ -384,21 +425,26 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
|||||||
|
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = ( struct CACHED_GENERIC* )NULL;
|
||||||
count = 0;
|
count = 0;
|
||||||
if (cache) {
|
if ( cache )
|
||||||
if (!(flags & CACHE_NOHASH) && cache->dohash) {
|
{
|
||||||
|
if ( !( flags & CACHE_NOHASH ) && cache->dohash )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* find out whether the entry if present
|
* find out whether the entry if present
|
||||||
*/
|
*/
|
||||||
h = cache->dohash( item );
|
h = cache->dohash( item );
|
||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while (link) {
|
while ( link )
|
||||||
|
{
|
||||||
if ( compare( link->entry, item ) )
|
if ( compare( link->entry, item ) )
|
||||||
link = link->next;
|
link = link->next;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if (current) {
|
if ( current )
|
||||||
|
{
|
||||||
drophashindex( cache, current, h );
|
drophashindex( cache, current, h );
|
||||||
do_invalidate( cache,
|
do_invalidate( cache,
|
||||||
current, flags );
|
current, flags );
|
||||||
@ -407,14 +453,17 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((flags & CACHE_NOHASH) || !cache->dohash) {
|
if ( ( flags & CACHE_NOHASH ) || !cache->dohash )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list
|
* Search sequentially in LRU list
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
previous = ( struct CACHED_GENERIC* )NULL;
|
previous = ( struct CACHED_GENERIC* )NULL;
|
||||||
while (current) {
|
while ( current )
|
||||||
if (!compare(current, item)) {
|
{
|
||||||
|
if ( !compare( current, item ) )
|
||||||
|
{
|
||||||
next = current->next;
|
next = current->next;
|
||||||
if ( cache->dohash )
|
if ( cache->dohash )
|
||||||
drophashindex( cache, current,
|
drophashindex( cache, current,
|
||||||
@ -422,7 +471,9 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
|||||||
do_invalidate( cache, current, flags );
|
do_invalidate( cache, current, flags );
|
||||||
current = next;
|
current = next;
|
||||||
count++;
|
count++;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
previous = current;
|
previous = current;
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
@ -438,7 +489,8 @@ int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
|||||||
int count;
|
int count;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
if (cache) {
|
if ( cache )
|
||||||
|
{
|
||||||
if ( cache->dohash )
|
if ( cache->dohash )
|
||||||
drophashindex( cache, item, cache->dohash( item ) );
|
drophashindex( cache, item, cache->dohash( item ) );
|
||||||
do_invalidate( cache, item, flags );
|
do_invalidate( cache, item, flags );
|
||||||
@ -455,8 +507,10 @@ static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
|||||||
{
|
{
|
||||||
struct CACHED_GENERIC *entry;
|
struct CACHED_GENERIC *entry;
|
||||||
|
|
||||||
if (cache) {
|
if ( cache )
|
||||||
for (entry=cache->most_recent_entry; entry; entry=entry->next) {
|
{
|
||||||
|
for ( entry = cache->most_recent_entry; entry; entry = entry->next )
|
||||||
|
{
|
||||||
if ( cache->dofree )
|
if ( cache->dofree )
|
||||||
cache->dofree( entry );
|
cache->dofree( entry );
|
||||||
if ( entry->variable )
|
if ( entry->variable )
|
||||||
@ -491,14 +545,18 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
|||||||
size += item_count*sizeof( struct HASH_ENTRY )
|
size += item_count*sizeof( struct HASH_ENTRY )
|
||||||
+ max_hash*sizeof( struct HASH_ENTRY* );
|
+ max_hash*sizeof( struct HASH_ENTRY* );
|
||||||
cache = ( struct CACHE_HEADER* )ntfs_malloc( size );
|
cache = ( struct CACHE_HEADER* )ntfs_malloc( size );
|
||||||
if (cache) {
|
if ( cache )
|
||||||
|
{
|
||||||
/* header */
|
/* header */
|
||||||
cache->name = name;
|
cache->name = name;
|
||||||
cache->dofree = dofree;
|
cache->dofree = dofree;
|
||||||
if (dohash && max_hash) {
|
if ( dohash && max_hash )
|
||||||
|
{
|
||||||
cache->dohash = dohash;
|
cache->dohash = dohash;
|
||||||
cache->max_hash = max_hash;
|
cache->max_hash = max_hash;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cache->dohash = ( cache_hash )NULL;
|
cache->dohash = ( cache_hash )NULL;
|
||||||
cache->max_hash = 0;
|
cache->max_hash = 0;
|
||||||
}
|
}
|
||||||
@ -511,7 +569,8 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
|||||||
cache->oldest_entry = ( struct CACHED_GENERIC* )NULL;
|
cache->oldest_entry = ( struct CACHED_GENERIC* )NULL;
|
||||||
cache->free_entry = &cache->entry[0];
|
cache->free_entry = &cache->entry[0];
|
||||||
pc = &cache->entry[0];
|
pc = &cache->entry[0];
|
||||||
for (i=0; i<(item_count - 1); i++) {
|
for ( i = 0; i < ( item_count - 1 ); i++ )
|
||||||
|
{
|
||||||
qc = ( struct CACHED_GENERIC* )( ( char* )pc
|
qc = ( struct CACHED_GENERIC* )( ( char* )pc
|
||||||
+ full_item_size );
|
+ full_item_size );
|
||||||
pc->next = qc;
|
pc->next = qc;
|
||||||
@ -524,17 +583,20 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
|||||||
pc->variable = ( void* )NULL;
|
pc->variable = ( void* )NULL;
|
||||||
pc->varsize = 0;
|
pc->varsize = 0;
|
||||||
|
|
||||||
if (max_hash) {
|
if ( max_hash )
|
||||||
|
{
|
||||||
/* chain the hash entries */
|
/* chain the hash entries */
|
||||||
ph = ( struct HASH_ENTRY* )( ( ( char* )pc ) + full_item_size );
|
ph = ( struct HASH_ENTRY* )( ( ( char* )pc ) + full_item_size );
|
||||||
cache->free_hash = ph;
|
cache->free_hash = ph;
|
||||||
for (i=0; i<(item_count - 1); i++) {
|
for ( i = 0; i < ( item_count - 1 ); i++ )
|
||||||
|
{
|
||||||
qh = &ph[1];
|
qh = &ph[1];
|
||||||
ph->next = qh;
|
ph->next = qh;
|
||||||
ph = qh;
|
ph = qh;
|
||||||
}
|
}
|
||||||
/* special for the last entry */
|
/* special for the last entry */
|
||||||
if (item_count) {
|
if ( item_count )
|
||||||
|
{
|
||||||
ph->next = ( struct HASH_ENTRY* )NULL;
|
ph->next = ( struct HASH_ENTRY* )NULL;
|
||||||
}
|
}
|
||||||
/* create and initialize the hash indexes */
|
/* create and initialize the hash indexes */
|
||||||
@ -542,7 +604,9 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
|||||||
cache->first_hash = px;
|
cache->first_hash = px;
|
||||||
for ( i = 0; i < max_hash; i++ )
|
for ( i = 0; i < max_hash; i++ )
|
||||||
px[i] = ( struct HASH_ENTRY* )NULL;
|
px[i] = ( struct HASH_ENTRY* )NULL;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cache->free_hash = ( struct HASH_ENTRY* )NULL;
|
cache->free_hash = ( struct HASH_ENTRY* )NULL;
|
||||||
cache->first_hash = ( struct HASH_ENTRY** )NULL;
|
cache->first_hash = ( struct HASH_ENTRY** )NULL;
|
||||||
}
|
}
|
||||||
|
@ -24,19 +24,22 @@
|
|||||||
|
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
|
|
||||||
struct CACHED_GENERIC {
|
struct CACHED_GENERIC
|
||||||
|
{
|
||||||
struct CACHED_GENERIC *next;
|
struct CACHED_GENERIC *next;
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
void *variable;
|
void *variable;
|
||||||
size_t varsize;
|
size_t varsize;
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
/* force alignment for pointers and u64 */
|
/* force alignment for pointers and u64 */
|
||||||
u64 u64align;
|
u64 u64align;
|
||||||
void *ptralign;
|
void *ptralign;
|
||||||
} fixed[0];
|
} fixed[0];
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHED_INODE {
|
struct CACHED_INODE
|
||||||
|
{
|
||||||
struct CACHED_INODE *next;
|
struct CACHED_INODE *next;
|
||||||
struct CACHED_INODE *previous;
|
struct CACHED_INODE *previous;
|
||||||
const char *pathname;
|
const char *pathname;
|
||||||
@ -45,7 +48,8 @@ struct CACHED_INODE {
|
|||||||
u64 inum;
|
u64 inum;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHED_NIDATA {
|
struct CACHED_NIDATA
|
||||||
|
{
|
||||||
struct CACHED_NIDATA *next;
|
struct CACHED_NIDATA *next;
|
||||||
struct CACHED_NIDATA *previous;
|
struct CACHED_NIDATA *previous;
|
||||||
const char *pathname; /* not used */
|
const char *pathname; /* not used */
|
||||||
@ -55,7 +59,8 @@ struct CACHED_NIDATA {
|
|||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHED_LOOKUP {
|
struct CACHED_LOOKUP
|
||||||
|
{
|
||||||
struct CACHED_LOOKUP *next;
|
struct CACHED_LOOKUP *next;
|
||||||
struct CACHED_LOOKUP *previous;
|
struct CACHED_LOOKUP *previous;
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -65,7 +70,8 @@ struct CACHED_LOOKUP {
|
|||||||
u64 inum;
|
u64 inum;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
CACHE_FREE = 1,
|
CACHE_FREE = 1,
|
||||||
CACHE_NOHASH = 2
|
CACHE_NOHASH = 2
|
||||||
} ;
|
} ;
|
||||||
@ -75,12 +81,14 @@ typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
|
|||||||
typedef void ( *cache_free )( const struct CACHED_GENERIC *cached );
|
typedef void ( *cache_free )( const struct CACHED_GENERIC *cached );
|
||||||
typedef int ( *cache_hash )( const struct CACHED_GENERIC *cached );
|
typedef int ( *cache_hash )( const struct CACHED_GENERIC *cached );
|
||||||
|
|
||||||
struct HASH_ENTRY {
|
struct HASH_ENTRY
|
||||||
|
{
|
||||||
struct HASH_ENTRY *next;
|
struct HASH_ENTRY *next;
|
||||||
struct CACHED_GENERIC *entry;
|
struct CACHED_GENERIC *entry;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHE_HEADER {
|
struct CACHE_HEADER
|
||||||
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
struct CACHED_GENERIC *most_recent_entry;
|
struct CACHED_GENERIC *most_recent_entry;
|
||||||
struct CACHED_GENERIC *oldest_entry;
|
struct CACHED_GENERIC *oldest_entry;
|
||||||
|
@ -45,23 +45,27 @@
|
|||||||
|
|
||||||
#define CACHE_FREE UINT_MAX
|
#define CACHE_FREE UINT_MAX
|
||||||
|
|
||||||
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize) {
|
NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize )
|
||||||
|
{
|
||||||
NTFS_CACHE* cache;
|
NTFS_CACHE* cache;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries;
|
NTFS_CACHE_ENTRY* cacheEntries;
|
||||||
|
|
||||||
if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL;
|
if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL;
|
||||||
|
|
||||||
if (numberOfPages < 4) {
|
if ( numberOfPages < 4 )
|
||||||
|
{
|
||||||
numberOfPages = 4;
|
numberOfPages = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sectorsPerPage < 32) {
|
if ( sectorsPerPage < 32 )
|
||||||
|
{
|
||||||
sectorsPerPage = 32;
|
sectorsPerPage = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
|
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
|
||||||
if (cache == NULL) {
|
if ( cache == NULL )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,12 +77,14 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
|||||||
|
|
||||||
|
|
||||||
cacheEntries = ( NTFS_CACHE_ENTRY* ) ntfs_alloc ( sizeof( NTFS_CACHE_ENTRY ) * numberOfPages );
|
cacheEntries = ( NTFS_CACHE_ENTRY* ) ntfs_alloc ( sizeof( NTFS_CACHE_ENTRY ) * numberOfPages );
|
||||||
if (cacheEntries == NULL) {
|
if ( cacheEntries == NULL )
|
||||||
|
{
|
||||||
ntfs_free ( cache );
|
ntfs_free ( cache );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < numberOfPages; i++) {
|
for ( i = 0; i < numberOfPages; i++ )
|
||||||
|
{
|
||||||
cacheEntries[i].sector = CACHE_FREE;
|
cacheEntries[i].sector = CACHE_FREE;
|
||||||
cacheEntries[i].count = 0;
|
cacheEntries[i].count = 0;
|
||||||
cacheEntries[i].last_access = 0;
|
cacheEntries[i].last_access = 0;
|
||||||
@ -91,7 +97,8 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
void _NTFS_cache_destructor ( NTFS_CACHE* cache )
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if ( cache == NULL ) return;
|
if ( cache == NULL ) return;
|
||||||
@ -100,7 +107,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
|||||||
_NTFS_cache_flush( cache );
|
_NTFS_cache_flush( cache );
|
||||||
|
|
||||||
// Free memory in reverse allocation order
|
// Free memory in reverse allocation order
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||||
|
{
|
||||||
ntfs_free ( cache->cacheEntries[i].cache );
|
ntfs_free ( cache->cacheEntries[i].cache );
|
||||||
}
|
}
|
||||||
ntfs_free ( cache->cacheEntries );
|
ntfs_free ( cache->cacheEntries );
|
||||||
@ -109,7 +117,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
|||||||
|
|
||||||
static u32 accessCounter = 0;
|
static u32 accessCounter = 0;
|
||||||
|
|
||||||
static u32 accessTime(){
|
static u32 accessTime()
|
||||||
|
{
|
||||||
accessCounter++;
|
accessCounter++;
|
||||||
return accessCounter;
|
return accessCounter;
|
||||||
}
|
}
|
||||||
@ -125,20 +134,24 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
|||||||
unsigned int oldUsed = 0;
|
unsigned int oldUsed = 0;
|
||||||
unsigned int oldAccess = UINT_MAX;
|
unsigned int oldAccess = UINT_MAX;
|
||||||
|
|
||||||
for(i=0;i<numberOfPages;i++) {
|
for ( i = 0; i < numberOfPages; i++ )
|
||||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
{
|
||||||
|
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
||||||
|
{
|
||||||
cacheEntries[i].last_access = accessTime();
|
cacheEntries[i].last_access = accessTime();
|
||||||
return &( cacheEntries[i] );
|
return &( cacheEntries[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
||||||
|
{
|
||||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
||||||
oldUsed = i;
|
oldUsed = i;
|
||||||
oldAccess = cacheEntries[i].last_access;
|
oldAccess = cacheEntries[i].last_access;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
||||||
|
{
|
||||||
if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||||
cacheEntries[oldUsed].dirty = false;
|
cacheEntries[oldUsed].dirty = false;
|
||||||
}
|
}
|
||||||
@ -155,7 +168,8 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
|||||||
return &( cacheEntries[oldUsed] );
|
return &( cacheEntries[oldUsed] );
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
|
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage( NTFS_CACHE *cache, sec_t sector, sec_t count )
|
||||||
|
{
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
@ -163,16 +177,22 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
|
|||||||
NTFS_CACHE_ENTRY *entry = NULL;
|
NTFS_CACHE_ENTRY *entry = NULL;
|
||||||
sec_t lowest = UINT_MAX;
|
sec_t lowest = UINT_MAX;
|
||||||
|
|
||||||
for(i=0;i<numberOfPages;i++) {
|
for ( i = 0; i < numberOfPages; i++ )
|
||||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
{
|
||||||
|
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||||
|
{
|
||||||
bool intersect;
|
bool intersect;
|
||||||
if (sector > cacheEntries[i].sector) {
|
if ( sector > cacheEntries[i].sector )
|
||||||
|
{
|
||||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
intersect = cacheEntries[i].sector - sector < count;
|
intersect = cacheEntries[i].sector - sector < count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||||
|
{
|
||||||
lowest = cacheEntries[i].sector;
|
lowest = cacheEntries[i].sector;
|
||||||
entry = &cacheEntries[i];
|
entry = &cacheEntries[i];
|
||||||
}
|
}
|
||||||
@ -189,7 +209,8 @@ bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,voi
|
|||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
uint8_t *dest = buffer;
|
uint8_t *dest = buffer;
|
||||||
|
|
||||||
while(numSectors>0) {
|
while ( numSectors > 0 )
|
||||||
|
{
|
||||||
entry = _NTFS_cache_getPage( cache, sector );
|
entry = _NTFS_cache_getPage( cache, sector );
|
||||||
if ( entry == NULL ) return false;
|
if ( entry == NULL ) return false;
|
||||||
|
|
||||||
@ -227,11 +248,13 @@ bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t secto
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
bool _NTFS_cache_readLittleEndianValue ( NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
|
||||||
|
{
|
||||||
uint8_t buf[4];
|
uint8_t buf[4];
|
||||||
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||||
|
|
||||||
switch(num_bytes) {
|
switch ( num_bytes )
|
||||||
|
{
|
||||||
case 1: *value = buf[0]; break;
|
case 1: *value = buf[0]; break;
|
||||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||||
@ -261,10 +284,12 @@ bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
bool _NTFS_cache_writeLittleEndianValue ( NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
||||||
|
{
|
||||||
uint8_t buf[4] = {0, 0, 0, 0};
|
uint8_t buf[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
switch(size) {
|
switch ( size )
|
||||||
|
{
|
||||||
case 1: buf[0] = value; break;
|
case 1: buf[0] = value; break;
|
||||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||||
@ -307,9 +332,11 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
|||||||
{
|
{
|
||||||
entry = _NTFS_cache_findPage( cache, sector, numSectors );
|
entry = _NTFS_cache_findPage( cache, sector, numSectors );
|
||||||
|
|
||||||
if(entry!=NULL) {
|
if ( entry != NULL )
|
||||||
|
{
|
||||||
|
|
||||||
if ( entry->sector > sector) {
|
if ( entry->sector > sector )
|
||||||
|
{
|
||||||
|
|
||||||
secs_to_write = entry->sector - sector;
|
secs_to_write = entry->sector - sector;
|
||||||
|
|
||||||
@ -332,7 +359,9 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
|||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cache->disc->writeSectors( sector, numSectors, src );
|
cache->disc->writeSectors( sector, numSectors, src );
|
||||||
numSectors = 0;
|
numSectors = 0;
|
||||||
}
|
}
|
||||||
@ -343,13 +372,17 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
|||||||
/*
|
/*
|
||||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||||
*/
|
*/
|
||||||
bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
bool _NTFS_cache_flush ( NTFS_CACHE* cache )
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
if ( cache == NULL ) return true;
|
if ( cache == NULL ) return true;
|
||||||
|
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||||
if (cache->cacheEntries[i].dirty) {
|
{
|
||||||
if (!cache->disc->writeSectors (cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
if ( cache->cacheEntries[i].dirty )
|
||||||
|
{
|
||||||
|
if ( !cache->disc->writeSectors ( cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,13 +392,15 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
void _NTFS_cache_invalidate ( NTFS_CACHE* cache )
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
if ( cache == NULL )
|
if ( cache == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_NTFS_cache_flush( cache );
|
_NTFS_cache_flush( cache );
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||||
|
{
|
||||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||||
cache->cacheEntries[i].last_access = 0;
|
cache->cacheEntries[i].last_access = 0;
|
||||||
cache->cacheEntries[i].count = 0;
|
cache->cacheEntries[i].count = 0;
|
||||||
|
@ -46,7 +46,8 @@
|
|||||||
#include <ogc/disc_io.h>
|
#include <ogc/disc_io.h>
|
||||||
#include <gccore.h>
|
#include <gccore.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
u64 last_access;
|
u64 last_access;
|
||||||
@ -54,7 +55,8 @@ typedef struct {
|
|||||||
u8* cache;
|
u8* cache;
|
||||||
} NTFS_CACHE_ENTRY;
|
} NTFS_CACHE_ENTRY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const DISC_INTERFACE* disc;
|
const DISC_INTERFACE* disc;
|
||||||
sec_t endOfPartition;
|
sec_t endOfPartition;
|
||||||
unsigned int numberOfPages;
|
unsigned int numberOfPages;
|
||||||
|
@ -60,7 +60,8 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace( "Entering.\n" );
|
||||||
rc = memcmp( data1, data2, min( data1_len, data2_len ) );
|
rc = memcmp( data1, data2, min( data1_len, data2_len ) );
|
||||||
if (!rc && (data1_len != data2_len)) {
|
if ( !rc && ( data1_len != data2_len ) )
|
||||||
|
{
|
||||||
if ( data1_len < data2_len )
|
if ( data1_len < data2_len )
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else
|
||||||
@ -90,7 +91,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
|||||||
u32 d1, d2;
|
u32 d1, d2;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace( "Entering.\n" );
|
||||||
if (data1_len != data2_len || data1_len != 4) {
|
if ( data1_len != data2_len || data1_len != 4 )
|
||||||
|
{
|
||||||
ntfs_log_error( "data1_len or/and data2_len not equal to 4.\n" );
|
ntfs_log_error( "data1_len or/and data2_len not equal to 4.\n" );
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
@ -98,7 +100,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
|||||||
d2 = le32_to_cpup( data2 );
|
d2 = le32_to_cpup( data2 );
|
||||||
if ( d1 < d2 )
|
if ( d1 < d2 )
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if ( d1 == d2 )
|
if ( d1 == d2 )
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else
|
else
|
||||||
@ -124,22 +127,26 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
|||||||
u32 d1, d2;
|
u32 d1, d2;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace( "Entering.\n" );
|
||||||
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) {
|
if ( ( data1_len != data2_len ) || ( data1_len <= 0 ) || ( data1_len & 3 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "data1_len or data2_len not valid\n" );
|
ntfs_log_error( "data1_len or data2_len not valid\n" );
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
p1 = ( const le32* )data1;
|
p1 = ( const le32* )data1;
|
||||||
p2 = ( const le32* )data2;
|
p2 = ( const le32* )data2;
|
||||||
len = data1_len;
|
len = data1_len;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
d1 = le32_to_cpup( p1 );
|
d1 = le32_to_cpup( p1 );
|
||||||
p1++;
|
p1++;
|
||||||
d2 = le32_to_cpup( p2 );
|
d2 = le32_to_cpup( p2 );
|
||||||
p2++;
|
p2++;
|
||||||
} while ((d1 == d2) && ((len -= 4) > 0));
|
}
|
||||||
|
while ( ( d1 == d2 ) && ( ( len -= 4 ) > 0 ) );
|
||||||
if ( d1 < d2 )
|
if ( d1 < d2 )
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if ( d1 == d2 )
|
if ( d1 == d2 )
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else
|
else
|
||||||
@ -171,7 +178,8 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
|||||||
const le32 *p1, *p2;
|
const le32 *p1, *p2;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace( "Entering.\n" );
|
||||||
if (data1_len != data2_len || data1_len != 8) {
|
if ( data1_len != data2_len || data1_len != 8 )
|
||||||
|
{
|
||||||
ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" );
|
ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" );
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
@ -181,17 +189,20 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
|||||||
d2 = le32_to_cpup( p2 );
|
d2 = le32_to_cpup( p2 );
|
||||||
if ( d1 < d2 )
|
if ( d1 < d2 )
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if ( d1 > d2 )
|
if ( d1 > d2 )
|
||||||
rc = 1;
|
rc = 1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
p1++;
|
p1++;
|
||||||
p2++;
|
p2++;
|
||||||
d1 = le32_to_cpup( p1 );
|
d1 = le32_to_cpup( p1 );
|
||||||
d2 = le32_to_cpup( p2 );
|
d2 = le32_to_cpup( p2 );
|
||||||
if ( d1 < d2 )
|
if ( d1 < d2 )
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if ( d1 > d2 )
|
if ( d1 > d2 )
|
||||||
rc = 1;
|
rc = 1;
|
||||||
else
|
else
|
||||||
@ -246,7 +257,8 @@ COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
|
|||||||
{
|
{
|
||||||
COLLATE collate;
|
COLLATE collate;
|
||||||
|
|
||||||
switch (cr) {
|
switch ( cr )
|
||||||
|
{
|
||||||
case COLLATION_BINARY :
|
case COLLATION_BINARY :
|
||||||
collate = ntfs_collate_binary;
|
collate = ntfs_collate_binary;
|
||||||
break;
|
break;
|
||||||
|
@ -41,23 +41,28 @@ int ffs(int x)
|
|||||||
|
|
||||||
if ( !x )
|
if ( !x )
|
||||||
return 0;
|
return 0;
|
||||||
if (!(x & 0xffff)) {
|
if ( !( x & 0xffff ) )
|
||||||
|
{
|
||||||
x >>= 16;
|
x >>= 16;
|
||||||
r += 16;
|
r += 16;
|
||||||
}
|
}
|
||||||
if (!(x & 0xff)) {
|
if ( !( x & 0xff ) )
|
||||||
|
{
|
||||||
x >>= 8;
|
x >>= 8;
|
||||||
r += 8;
|
r += 8;
|
||||||
}
|
}
|
||||||
if (!(x & 0xf)) {
|
if ( !( x & 0xf ) )
|
||||||
|
{
|
||||||
x >>= 4;
|
x >>= 4;
|
||||||
r += 4;
|
r += 4;
|
||||||
}
|
}
|
||||||
if (!(x & 3)) {
|
if ( !( x & 3 ) )
|
||||||
|
{
|
||||||
x >>= 2;
|
x >>= 2;
|
||||||
r += 2;
|
r += 2;
|
||||||
}
|
}
|
||||||
if (!(x & 1)) {
|
if ( !( x & 1 ) )
|
||||||
|
{
|
||||||
x >>= 1;
|
x >>= 1;
|
||||||
r += 1;
|
r += 1;
|
||||||
}
|
}
|
||||||
@ -120,10 +125,12 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int daemon(int nochdir, int noclose) {
|
int daemon( int nochdir, int noclose )
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
switch (fork()) {
|
switch ( fork() )
|
||||||
|
{
|
||||||
case -1:
|
case -1:
|
||||||
return ( -1 );
|
return ( -1 );
|
||||||
case 0:
|
case 0:
|
||||||
@ -138,7 +145,8 @@ int daemon(int nochdir, int noclose) {
|
|||||||
if ( !nochdir )
|
if ( !nochdir )
|
||||||
( void )chdir( "/" );
|
( void )chdir( "/" );
|
||||||
|
|
||||||
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
if ( !noclose && ( fd = open( "/dev/null", O_RDWR, 0 ) ) != -1 )
|
||||||
|
{
|
||||||
( void )dup2( fd, 0 );
|
( void )dup2( fd, 0 );
|
||||||
( void )dup2( fd, 1 );
|
( void )dup2( fd, 1 );
|
||||||
( void )dup2( fd, 2 );
|
( void )dup2( fd, 2 );
|
||||||
@ -218,7 +226,8 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
|||||||
*
|
*
|
||||||
* If *stringp is NULL, strsep returns NULL.
|
* If *stringp is NULL, strsep returns NULL.
|
||||||
*/
|
*/
|
||||||
char *strsep(char **stringp, const char *delim) {
|
char *strsep( char **stringp, const char *delim )
|
||||||
|
{
|
||||||
char *s;
|
char *s;
|
||||||
const char *spanp;
|
const char *spanp;
|
||||||
int c, sc;
|
int c, sc;
|
||||||
@ -226,11 +235,14 @@ char *strsep(char **stringp, const char *delim) {
|
|||||||
|
|
||||||
if ( ( s = *stringp ) == NULL )
|
if ( ( s = *stringp ) == NULL )
|
||||||
return ( NULL );
|
return ( NULL );
|
||||||
for (tok = s;;) {
|
for ( tok = s;; )
|
||||||
|
{
|
||||||
c = *s++;
|
c = *s++;
|
||||||
spanp = delim;
|
spanp = delim;
|
||||||
do {
|
do
|
||||||
if ((sc = *spanp++) == c) {
|
{
|
||||||
|
if ( ( sc = *spanp++ ) == c )
|
||||||
|
{
|
||||||
if ( c == 0 )
|
if ( c == 0 )
|
||||||
s = NULL;
|
s = NULL;
|
||||||
else
|
else
|
||||||
@ -238,7 +250,8 @@ char *strsep(char **stringp, const char *delim) {
|
|||||||
*stringp = s;
|
*stringp = s;
|
||||||
return ( tok );
|
return ( tok );
|
||||||
}
|
}
|
||||||
} while (sc != 0);
|
}
|
||||||
|
while ( sc != 0 );
|
||||||
}
|
}
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -47,18 +47,22 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||||
"LCN_unknown " };
|
"LCN_unknown "
|
||||||
|
};
|
||||||
|
|
||||||
ntfs_log_debug( "NTFS-fs DEBUG: Dumping runlist (values in hex):\n" );
|
ntfs_log_debug( "NTFS-fs DEBUG: Dumping runlist (values in hex):\n" );
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Run list not present.\n" );
|
ntfs_log_debug( "Run list not present.\n" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ntfs_log_debug( "VCN LCN Run length\n" );
|
ntfs_log_debug( "VCN LCN Run length\n" );
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
LCN lcn = ( rl + i )->lcn;
|
LCN lcn = ( rl + i )->lcn;
|
||||||
|
|
||||||
if (lcn < (LCN)0) {
|
if ( lcn < ( LCN )0 )
|
||||||
|
{
|
||||||
int idx = -lcn - 1;
|
int idx = -lcn - 1;
|
||||||
|
|
||||||
if ( idx > -LCN_EINVAL - 1 )
|
if ( idx > -LCN_EINVAL - 1 )
|
||||||
@ -67,12 +71,14 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
|
|||||||
( long long )rl[i].vcn, lcn_str[idx],
|
( long long )rl[i].vcn, lcn_str[idx],
|
||||||
( long long )rl[i].length,
|
( long long )rl[i].length,
|
||||||
rl[i].length ? "" : " (runlist end)" );
|
rl[i].length ? "" : " (runlist end)" );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n",
|
ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n",
|
||||||
( long long )rl[i].vcn, ( long long )rl[i].lcn,
|
( long long )rl[i].vcn, ( long long )rl[i].lcn,
|
||||||
( long long )rl[i].length,
|
( long long )rl[i].length,
|
||||||
rl[i].length ? "" : " (runlist end)" );
|
rl[i].length ? "" : " (runlist end)" );
|
||||||
} while (rl[i++].length);
|
}
|
||||||
|
while ( rl[i++].length );
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -108,14 +108,17 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
|||||||
{
|
{
|
||||||
struct ntfs_device *dev;
|
struct ntfs_device *dev;
|
||||||
|
|
||||||
if (!name) {
|
if ( !name )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = ntfs_malloc( sizeof( struct ntfs_device ) );
|
dev = ntfs_malloc( sizeof( struct ntfs_device ) );
|
||||||
if (dev) {
|
if ( dev )
|
||||||
if (!(dev->d_name = strdup(name))) {
|
{
|
||||||
|
if ( !( dev->d_name = strdup( name ) ) )
|
||||||
|
{
|
||||||
int eo = errno;
|
int eo = errno;
|
||||||
free( dev );
|
free( dev );
|
||||||
errno = eo;
|
errno = eo;
|
||||||
@ -141,11 +144,13 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
|||||||
*/
|
*/
|
||||||
int ntfs_device_free( struct ntfs_device *dev )
|
int ntfs_device_free( struct ntfs_device *dev )
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if ( !dev )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (NDevOpen(dev)) {
|
if ( NDevOpen( dev ) )
|
||||||
|
{
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -180,7 +185,8 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
|||||||
|
|
||||||
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
||||||
|
|
||||||
if (!b || count < 0 || pos < 0) {
|
if ( !b || count < 0 || pos < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -189,7 +195,8 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
|||||||
|
|
||||||
dops = dev->d_ops;
|
dops = dev->d_ops;
|
||||||
|
|
||||||
for (total = 0; count; count -= br, total += br) {
|
for ( total = 0; count; count -= br, total += br )
|
||||||
|
{
|
||||||
br = dops->pread( dev, ( char* )b + total, count, pos + total );
|
br = dops->pread( dev, ( char* )b + total, count, pos + total );
|
||||||
/* If everything ok, continue. */
|
/* If everything ok, continue. */
|
||||||
if ( br > 0 )
|
if ( br > 0 )
|
||||||
@ -231,13 +238,15 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
|
|
||||||
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
||||||
|
|
||||||
if (!b || count < 0 || pos < 0) {
|
if ( !b || count < 0 || pos < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ( !count )
|
if ( !count )
|
||||||
return 0;
|
return 0;
|
||||||
if (NDevReadOnly(dev)) {
|
if ( NDevReadOnly( dev ) )
|
||||||
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -245,7 +254,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
dops = dev->d_ops;
|
dops = dev->d_ops;
|
||||||
|
|
||||||
NDevSetDirty( dev );
|
NDevSetDirty( dev );
|
||||||
for (total = 0; count; count -= written, total += written) {
|
for ( total = 0; count; count -= written, total += written )
|
||||||
|
{
|
||||||
written = dops->pwrite( dev, ( const char* )b + total, count,
|
written = dops->pwrite( dev, ( const char* )b + total, count,
|
||||||
pos + total );
|
pos + total );
|
||||||
/* If everything ok, continue. */
|
/* If everything ok, continue. */
|
||||||
@ -299,7 +309,8 @@ s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
{
|
{
|
||||||
s64 br, i;
|
s64 br, i;
|
||||||
|
|
||||||
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
|
if ( bksize & ( bksize - 1 ) || bksize % NTFS_BLOCK_SIZE )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -356,19 +367,22 @@ s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
{
|
{
|
||||||
s64 written, i;
|
s64 written, i;
|
||||||
|
|
||||||
if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
|
if ( count < 0 || bksize % NTFS_BLOCK_SIZE )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( !count )
|
if ( !count )
|
||||||
return 0;
|
return 0;
|
||||||
/* Prepare data for writing. */
|
/* Prepare data for writing. */
|
||||||
for (i = 0; i < count; ++i) {
|
for ( i = 0; i < count; ++i )
|
||||||
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = ntfs_mst_pre_write_fixup( ( NTFS_RECORD* )
|
err = ntfs_mst_pre_write_fixup( ( NTFS_RECORD* )
|
||||||
( ( u8* )b + i * bksize ), bksize );
|
( ( u8* )b + i * bksize ), bksize );
|
||||||
if (err < 0) {
|
if ( err < 0 )
|
||||||
|
{
|
||||||
/* Abort write at this position. */
|
/* Abort write at this position. */
|
||||||
if ( !i )
|
if ( !i )
|
||||||
return err;
|
return err;
|
||||||
@ -403,11 +417,13 @@ s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
|||||||
{
|
{
|
||||||
s64 br;
|
s64 br;
|
||||||
|
|
||||||
if (!vol || lcn < 0 || count < 0) {
|
if ( !vol || lcn < 0 || count < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (vol->nr_clusters < lcn + count) {
|
if ( vol->nr_clusters < lcn + count )
|
||||||
|
{
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror( "Trying to read outside of volume "
|
ntfs_log_perror( "Trying to read outside of volume "
|
||||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
||||||
@ -416,7 +432,8 @@ s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
|||||||
}
|
}
|
||||||
br = ntfs_pread( vol->dev, lcn << vol->cluster_size_bits,
|
br = ntfs_pread( vol->dev, lcn << vol->cluster_size_bits,
|
||||||
count << vol->cluster_size_bits, b );
|
count << vol->cluster_size_bits, b );
|
||||||
if (br < 0) {
|
if ( br < 0 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Error reading cluster(s)" );
|
ntfs_log_perror( "Error reading cluster(s)" );
|
||||||
return br;
|
return br;
|
||||||
}
|
}
|
||||||
@ -439,11 +456,13 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
|||||||
{
|
{
|
||||||
s64 bw;
|
s64 bw;
|
||||||
|
|
||||||
if (!vol || lcn < 0 || count < 0) {
|
if ( !vol || lcn < 0 || count < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (vol->nr_clusters < lcn + count) {
|
if ( vol->nr_clusters < lcn + count )
|
||||||
|
{
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror( "Trying to write outside of volume "
|
ntfs_log_perror( "Trying to write outside of volume "
|
||||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
||||||
@ -455,7 +474,8 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
|||||||
count << vol->cluster_size_bits, b );
|
count << vol->cluster_size_bits, b );
|
||||||
else
|
else
|
||||||
bw = count << vol->cluster_size_bits;
|
bw = count << vol->cluster_size_bits;
|
||||||
if (bw < 0) {
|
if ( bw < 0 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Error writing cluster(s)" );
|
ntfs_log_perror( "Error writing cluster(s)" );
|
||||||
return bw;
|
return bw;
|
||||||
}
|
}
|
||||||
@ -498,14 +518,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
{
|
{
|
||||||
s64 high, low;
|
s64 high, low;
|
||||||
|
|
||||||
if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
|
if ( !dev || block_size <= 0 || ( block_size - 1 ) & block_size )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef BLKGETSIZE64
|
#ifdef BLKGETSIZE64
|
||||||
{ u64 size;
|
{ u64 size;
|
||||||
|
|
||||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
|
if ( dev->d_ops->ioctl( dev, BLKGETSIZE64, &size ) >= 0 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
ntfs_log_debug( "BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||||
( unsigned long long )size,
|
( unsigned long long )size,
|
||||||
( unsigned long long )size );
|
( unsigned long long )size );
|
||||||
@ -516,7 +538,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
#ifdef BLKGETSIZE
|
#ifdef BLKGETSIZE
|
||||||
{ unsigned long size;
|
{ unsigned long size;
|
||||||
|
|
||||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
|
if ( dev->d_ops->ioctl( dev, BLKGETSIZE, &size ) >= 0 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
ntfs_log_debug( "BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
||||||
size, size );
|
size, size );
|
||||||
return ( s64 )size * 512 / block_size;
|
return ( s64 )size * 512 / block_size;
|
||||||
@ -526,7 +549,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
#ifdef FDGETPRM
|
#ifdef FDGETPRM
|
||||||
{ struct floppy_struct this_floppy;
|
{ struct floppy_struct this_floppy;
|
||||||
|
|
||||||
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
|
if ( dev->d_ops->ioctl( dev, FDGETPRM, &this_floppy ) >= 0 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
ntfs_log_debug( "FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
||||||
( unsigned long )this_floppy.size,
|
( unsigned long )this_floppy.size,
|
||||||
( unsigned long )this_floppy.size );
|
( unsigned long )this_floppy.size );
|
||||||
@ -541,7 +565,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
low = 0LL;
|
low = 0LL;
|
||||||
for ( high = 1024LL; !ntfs_device_offset_valid( dev, high ); high <<= 1 )
|
for ( high = 1024LL; !ntfs_device_offset_valid( dev, high ); high <<= 1 )
|
||||||
low = high;
|
low = high;
|
||||||
while (low < high - 1LL) {
|
while ( low < high - 1LL )
|
||||||
|
{
|
||||||
const s64 mid = ( low + high ) / 2;
|
const s64 mid = ( low + high ) / 2;
|
||||||
|
|
||||||
if ( !ntfs_device_offset_valid( dev, mid ) )
|
if ( !ntfs_device_offset_valid( dev, mid ) )
|
||||||
@ -567,14 +592,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
*/
|
*/
|
||||||
s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev )
|
s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev )
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if ( !dev )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
ntfs_log_debug( "HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
||||||
geo.start, geo.start );
|
geo.start, geo.start );
|
||||||
return geo.start;
|
return geo.start;
|
||||||
@ -600,14 +627,16 @@ s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
|
|||||||
*/
|
*/
|
||||||
int ntfs_device_heads_get( struct ntfs_device *dev )
|
int ntfs_device_heads_get( struct ntfs_device *dev )
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if ( !dev )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "HDIO_GETGEO heads = %u (0x%x)\n",
|
ntfs_log_debug( "HDIO_GETGEO heads = %u (0x%x)\n",
|
||||||
( unsigned )geo.heads,
|
( unsigned )geo.heads,
|
||||||
( unsigned )geo.heads );
|
( unsigned )geo.heads );
|
||||||
@ -634,14 +663,16 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
|
|||||||
*/
|
*/
|
||||||
int ntfs_device_sectors_per_track_get( struct ntfs_device *dev )
|
int ntfs_device_sectors_per_track_get( struct ntfs_device *dev )
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if ( !dev )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
ntfs_log_debug( "HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
||||||
( unsigned )geo.sectors,
|
( unsigned )geo.sectors,
|
||||||
( unsigned )geo.sectors );
|
( unsigned )geo.sectors );
|
||||||
@ -668,7 +699,8 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
|
|||||||
*/
|
*/
|
||||||
int ntfs_device_sector_size_get( struct ntfs_device *dev )
|
int ntfs_device_sector_size_get( struct ntfs_device *dev )
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if ( !dev )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -676,7 +708,8 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
|||||||
{
|
{
|
||||||
int sect_size = 0;
|
int sect_size = 0;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) {
|
if ( !dev->d_ops->ioctl( dev, BLKSSZGET, §_size ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "BLKSSZGET sector size = %d bytes\n",
|
ntfs_log_debug( "BLKSSZGET sector size = %d bytes\n",
|
||||||
sect_size );
|
sect_size );
|
||||||
return sect_size;
|
return sect_size;
|
||||||
@ -704,14 +737,16 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
|||||||
int ntfs_device_block_size_set( struct ntfs_device *dev,
|
int ntfs_device_block_size_set( struct ntfs_device *dev,
|
||||||
int block_size __attribute__( ( unused ) ) )
|
int block_size __attribute__( ( unused ) ) )
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if ( !dev )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef BLKBSZSET
|
#ifdef BLKBSZSET
|
||||||
{
|
{
|
||||||
size_t s_block_size = block_size;
|
size_t s_block_size = block_size;
|
||||||
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
|
if ( !dev->d_ops->ioctl( dev, BLKBSZSET, &s_block_size ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Used BLKBSZSET to set block size to "
|
ntfs_log_debug( "Used BLKBSZSET to set block size to "
|
||||||
"%d bytes.\n", block_size );
|
"%d bytes.\n", block_size );
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -36,7 +36,8 @@
|
|||||||
*
|
*
|
||||||
* Defined bits for the state field in the ntfs_device structure.
|
* Defined bits for the state field in the ntfs_device structure.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ND_Open, /* 1: Device is open. */
|
ND_Open, /* 1: Device is open. */
|
||||||
ND_ReadOnly, /* 1: Device is read-only. */
|
ND_ReadOnly, /* 1: Device is read-only. */
|
||||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||||
@ -69,7 +70,8 @@ typedef enum {
|
|||||||
* The ntfs device structure defining all operations needed to access the low
|
* The ntfs device structure defining all operations needed to access the low
|
||||||
* level device underlying the ntfs volume.
|
* level device underlying the ntfs volume.
|
||||||
*/
|
*/
|
||||||
struct ntfs_device {
|
struct ntfs_device
|
||||||
|
{
|
||||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||||
unsigned long d_state; /* State of the device. */
|
unsigned long d_state; /* State of the device. */
|
||||||
char *d_name; /* Name of device. */
|
char *d_name; /* Name of device. */
|
||||||
@ -85,7 +87,8 @@ struct stat;
|
|||||||
* The ntfs device operations defining all operations that can be performed on
|
* The ntfs device operations defining all operations that can be performed on
|
||||||
* the low level device described by an ntfs device structure.
|
* the low level device described by an ntfs device structure.
|
||||||
*/
|
*/
|
||||||
struct ntfs_device_operations {
|
struct ntfs_device_operations
|
||||||
|
{
|
||||||
int ( *open )( struct ntfs_device *dev, int flags );
|
int ( *open )( struct ntfs_device *dev, int flags );
|
||||||
int ( *close )( struct ntfs_device *dev );
|
int ( *close )( struct ntfs_device *dev );
|
||||||
s64 ( *seek )( struct ntfs_device *dev, s64 offset, int whence );
|
s64 ( *seek )( struct ntfs_device *dev, s64 offset, int whence );
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
/**
|
/**
|
||||||
* struct hd_geometry -
|
* struct hd_geometry -
|
||||||
*/
|
*/
|
||||||
struct hd_geometry {
|
struct hd_geometry
|
||||||
|
{
|
||||||
unsigned char heads;
|
unsigned char heads;
|
||||||
unsigned char sectors;
|
unsigned char sectors;
|
||||||
unsigned short cylinders;
|
unsigned short cylinders;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -60,7 +60,8 @@
|
|||||||
|
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
|
|
||||||
static ntfschar logged_utility_stream_name[] = {
|
static ntfschar logged_utility_stream_name[] =
|
||||||
|
{
|
||||||
const_cpu_to_le16( '$' ),
|
const_cpu_to_le16( '$' ),
|
||||||
const_cpu_to_le16( 'E' ),
|
const_cpu_to_le16( 'E' ),
|
||||||
const_cpu_to_le16( 'F' ),
|
const_cpu_to_le16( 'F' ),
|
||||||
@ -78,32 +79,43 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
|||||||
EFS_ATTR_HEADER *efs_info;
|
EFS_ATTR_HEADER *efs_info;
|
||||||
s64 attr_size = 0;
|
s64 attr_size = 0;
|
||||||
|
|
||||||
if (ni) {
|
if ( ni )
|
||||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
{
|
||||||
|
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||||
|
{
|
||||||
efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni,
|
efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni,
|
||||||
AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0,
|
AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0,
|
||||||
&attr_size );
|
&attr_size );
|
||||||
if ( efs_info
|
if ( efs_info
|
||||||
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
&& ( le32_to_cpu( efs_info->length ) == attr_size ) )
|
||||||
if (attr_size <= (s64)size) {
|
{
|
||||||
|
if ( attr_size <= ( s64 )size )
|
||||||
|
{
|
||||||
if ( value )
|
if ( value )
|
||||||
memcpy( value, efs_info, attr_size );
|
memcpy( value, efs_info, attr_size );
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
if (size) {
|
else if ( size )
|
||||||
|
{
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
free ( efs_info );
|
free ( efs_info );
|
||||||
} else {
|
}
|
||||||
if (efs_info) {
|
else
|
||||||
|
{
|
||||||
|
if ( efs_info )
|
||||||
|
{
|
||||||
free( efs_info );
|
free( efs_info );
|
||||||
ntfs_log_error( "Bad efs_info for inode %lld\n",
|
ntfs_log_error( "Bad efs_info for inode %lld\n",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "Could not get efsinfo"
|
ntfs_log_error( "Could not get efsinfo"
|
||||||
" for inode %lld\n",
|
" for inode %lld\n",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
@ -111,7 +123,9 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
|||||||
errno = EIO;
|
errno = EIO;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
ntfs_log_trace( "Inode %lld is not encrypted\n",
|
ntfs_log_trace( "Inode %lld is not encrypted\n",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
@ -145,45 +159,57 @@ static int fixup_loop(ntfs_inode *ni)
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
maxcnt = 0;
|
maxcnt = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
restart = FALSE;
|
restart = FALSE;
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||||
if (!ctx) {
|
if ( !ctx )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
while ( !restart && !res
|
while ( !restart && !res
|
||||||
&& !ntfs_attr_lookup( AT_DATA, NULL, 0,
|
&& !ntfs_attr_lookup( AT_DATA, NULL, 0,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
cnt++;
|
cnt++;
|
||||||
a = ctx->attr;
|
a = ctx->attr;
|
||||||
na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA,
|
na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA,
|
||||||
( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ),
|
( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ),
|
||||||
a->name_length );
|
a->name_length );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
ntfs_log_error( "can't open DATA Attribute\n" );
|
ntfs_log_error( "can't open DATA Attribute\n" );
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
|
if ( na && !( ctx->attr->flags & ATTR_IS_ENCRYPTED ) )
|
||||||
|
{
|
||||||
if ( !NAttrNonResident( na )
|
if ( !NAttrNonResident( na )
|
||||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* ntfs_attr_make_non_resident fails if there
|
* ntfs_attr_make_non_resident fails if there
|
||||||
* is not enough space in the MFT record.
|
* is not enough space in the MFT record.
|
||||||
* When this happens, force making non-resident
|
* When this happens, force making non-resident
|
||||||
* so that some other attribute is expelled.
|
* so that some other attribute is expelled.
|
||||||
*/
|
*/
|
||||||
if (ntfs_attr_force_non_resident(na)) {
|
if ( ntfs_attr_force_non_resident( na ) )
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* make sure there is some progress */
|
/* make sure there is some progress */
|
||||||
if (cnt <= maxcnt) {
|
if ( cnt <= maxcnt )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_error( "Multiple failure"
|
ntfs_log_error( "Multiple failure"
|
||||||
" making non resident\n" );
|
" making non resident\n" );
|
||||||
res = -1;
|
res = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
ctx = ( ntfs_attr_search_ctx* )NULL;
|
ctx = ( ntfs_attr_search_ctx* )NULL;
|
||||||
restart = TRUE;
|
restart = TRUE;
|
||||||
@ -192,7 +218,8 @@ static int fixup_loop(ntfs_inode *ni)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !restart && !res
|
if ( !restart && !res
|
||||||
&& ntfs_efs_fixup_attribute(ctx, na)) {
|
&& ntfs_efs_fixup_attribute( ctx, na ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" );
|
ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" );
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
@ -201,7 +228,8 @@ static int fixup_loop(ntfs_inode *ni)
|
|||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
}
|
}
|
||||||
first = FALSE;
|
first = FALSE;
|
||||||
} while (restart && !res);
|
}
|
||||||
|
while ( restart && !res );
|
||||||
if ( ctx )
|
if ( ctx )
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
return ( res );
|
return ( res );
|
||||||
@ -223,13 +251,18 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
const EFS_ATTR_HEADER *info_header;
|
const EFS_ATTR_HEADER *info_header;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if (ni && value && size) {
|
if ( ni && value && size )
|
||||||
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
{
|
||||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
if ( ni->flags & ( FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED ) )
|
||||||
|
{
|
||||||
|
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Inode %lld already encrypted\n",
|
ntfs_log_trace( "Inode %lld already encrypted\n",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Possible problem : if encrypted file was
|
* Possible problem : if encrypted file was
|
||||||
* restored in a compressed directory, it was
|
* restored in a compressed directory, it was
|
||||||
@ -244,13 +277,16 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
}
|
}
|
||||||
info_header = ( const EFS_ATTR_HEADER* )value;
|
info_header = ( const EFS_ATTR_HEADER* )value;
|
||||||
/* make sure we get a likely efsinfo */
|
/* make sure we get a likely efsinfo */
|
||||||
if (le32_to_cpu(info_header->length) != size) {
|
if ( le32_to_cpu( info_header->length ) != size )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return ( -1 );
|
return ( -1 );
|
||||||
}
|
}
|
||||||
if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM,
|
if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM,
|
||||||
(ntfschar*)NULL,0)) {
|
( ntfschar* )NULL, 0 ) )
|
||||||
if (!(flags & XATTR_REPLACE)) {
|
{
|
||||||
|
if ( !( flags & XATTR_REPLACE ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* no logged_utility_stream attribute : add one,
|
* no logged_utility_stream attribute : add one,
|
||||||
* apparently, this does not feed the new value in
|
* apparently, this does not feed the new value in
|
||||||
@ -258,28 +294,36 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM,
|
res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM,
|
||||||
logged_utility_stream_name, 4,
|
logged_utility_stream_name, 4,
|
||||||
( u8* )NULL, ( s64 )size );
|
( u8* )NULL, ( s64 )size );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if (!res) {
|
if ( !res )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* open and update the existing efs data
|
* open and update the existing efs data
|
||||||
*/
|
*/
|
||||||
na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM,
|
na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM,
|
||||||
logged_utility_stream_name, 4 );
|
logged_utility_stream_name, 4 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
/* resize attribute */
|
/* resize attribute */
|
||||||
res = ntfs_attr_truncate( na, ( s64 )size );
|
res = ntfs_attr_truncate( na, ( s64 )size );
|
||||||
/* overwrite value if any */
|
/* overwrite value if any */
|
||||||
if (!res && value) {
|
if ( !res && value )
|
||||||
|
{
|
||||||
written = ( int )ntfs_attr_pwrite( na,
|
written = ( int )ntfs_attr_pwrite( na,
|
||||||
( s64 )0, ( s64 )size, value );
|
( s64 )0, ( s64 )size, value );
|
||||||
if (written != (s64)size) {
|
if ( written != ( s64 )size )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to "
|
ntfs_log_error( "Failed to "
|
||||||
"update efs data\n" );
|
"update efs data\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -287,12 +331,15 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if (!res) {
|
if ( !res )
|
||||||
|
{
|
||||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
if ( !( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||||
|
{
|
||||||
/* iterate over AT_DATA attributes */
|
/* iterate over AT_DATA attributes */
|
||||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||||
|
|
||||||
@ -303,7 +350,9 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
NInoSetDirty( ni );
|
NInoSetDirty( ni );
|
||||||
NInoFileNameSetDirty( ni );
|
NInoFileNameSetDirty( ni );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
@ -330,24 +379,31 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
BOOL close_ctx = FALSE;
|
BOOL close_ctx = FALSE;
|
||||||
|
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
ntfs_log_error( "no na specified for efs_fixup_attribute\n" );
|
ntfs_log_error( "no na specified for efs_fixup_attribute\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (!ctx) {
|
if ( !ctx )
|
||||||
|
{
|
||||||
ctx = ntfs_attr_get_search_ctx( na->ni, NULL );
|
ctx = ntfs_attr_get_search_ctx( na->ni, NULL );
|
||||||
if (!ctx) {
|
if ( !ctx )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
close_ctx = TRUE;
|
close_ctx = TRUE;
|
||||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (!NAttrNonResident(na)) {
|
else
|
||||||
|
{
|
||||||
|
if ( !NAttrNonResident( na ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Cannot make non resident"
|
ntfs_log_error( "Cannot make non resident"
|
||||||
" when a context has been allocated\n" );
|
" when a context has been allocated\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -356,19 +412,23 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
|
|
||||||
/* no extra bytes are added to void attributes */
|
/* no extra bytes are added to void attributes */
|
||||||
oldsize = na->data_size;
|
oldsize = na->data_size;
|
||||||
if (oldsize) {
|
if ( oldsize )
|
||||||
|
{
|
||||||
/* make sure size is valid for a raw encrypted stream */
|
/* make sure size is valid for a raw encrypted stream */
|
||||||
if ((oldsize & 511) != 2) {
|
if ( ( oldsize & 511 ) != 2 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Bad raw encrypted stream\n" );
|
ntfs_log_error( "Bad raw encrypted stream\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* read padding length from last two bytes of attribute */
|
/* read padding length from last two bytes of attribute */
|
||||||
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
|
if ( ntfs_attr_pread( na, oldsize - 2, 2, &appended_bytes ) != 2 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Error reading padding length\n" );
|
ntfs_log_error( "Error reading padding length\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
padding_length = le16_to_cpu( appended_bytes );
|
padding_length = le16_to_cpu( appended_bytes );
|
||||||
if (padding_length > 511 || padding_length > na->data_size-2) {
|
if ( padding_length > 511 || padding_length > na->data_size - 2 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_error( "invalid padding length %d for data_size %lld\n",
|
ntfs_log_error( "invalid padding length %d for data_size %lld\n",
|
||||||
padding_length, ( long long )oldsize );
|
padding_length, ( long long )oldsize );
|
||||||
@ -380,11 +440,13 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
* for the last two bytes, but do not truncate to new size
|
* for the last two bytes, but do not truncate to new size
|
||||||
* to avoid losing useful data
|
* to avoid losing useful data
|
||||||
*/
|
*/
|
||||||
if (ntfs_attr_truncate(na, oldsize - 2)) {
|
if ( ntfs_attr_truncate( na, oldsize - 2 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Error truncating attribute\n" );
|
ntfs_log_error( "Error truncating attribute\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
newsize = 0;
|
newsize = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -394,12 +456,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
* resident.
|
* resident.
|
||||||
*/
|
*/
|
||||||
if ( !NAttrNonResident( na )
|
if ( !NAttrNonResident( na )
|
||||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||||
|
{
|
||||||
if ( !close_ctx
|
if ( !close_ctx
|
||||||
|| ntfs_attr_force_non_resident(na)) {
|
|| ntfs_attr_force_non_resident( na ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Error making DATA attribute non-resident\n" );
|
ntfs_log_error( "Error making DATA attribute non-resident\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* must reinitialize context after forcing
|
* must reinitialize context after forcing
|
||||||
* non-resident. We need a context for updating
|
* non-resident. We need a context for updating
|
||||||
@ -408,14 +474,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
*/
|
*/
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ni = na->ni;
|
ni = na->ni;
|
||||||
if (!na->name_len) {
|
if ( !na->name_len )
|
||||||
|
{
|
||||||
ni->data_size = newsize;
|
ni->data_size = newsize;
|
||||||
ni->allocated_size = na->allocated_size;
|
ni->allocated_size = na->allocated_size;
|
||||||
}
|
}
|
||||||
|
@ -80,32 +80,37 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if (!interface) {
|
if ( !interface )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the device interface and ensure that it is inserted
|
// Start the device interface and ensure that it is inserted
|
||||||
if (!interface->startup()) {
|
if ( !interface->startup() )
|
||||||
|
{
|
||||||
ntfs_log_perror( "device failed to start\n" );
|
ntfs_log_perror( "device failed to start\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!interface->isInserted()) {
|
if ( !interface->isInserted() )
|
||||||
|
{
|
||||||
ntfs_log_perror( "device media is not inserted\n" );
|
ntfs_log_perror( "device media is not inserted\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device isn't already open (used by another volume?)
|
// Check that the device isn't already open (used by another volume?)
|
||||||
if (NDevOpen(dev)) {
|
if ( NDevOpen( dev ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "device is busy (already open)\n" );
|
ntfs_log_perror( "device is busy (already open)\n" );
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
return -1;
|
return -1;
|
||||||
@ -113,12 +118,16 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
|||||||
|
|
||||||
// Check that there is a valid NTFS boot sector at the start of the device
|
// Check that there is a valid NTFS boot sector at the start of the device
|
||||||
NTFS_BOOT_SECTOR boot;
|
NTFS_BOOT_SECTOR boot;
|
||||||
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
if ( interface->readSectors( fd->startSector, 1, &boot ) )
|
||||||
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
{
|
||||||
|
if ( !ntfs_boot_sector_is_ntfs( &boot ) )
|
||||||
|
{
|
||||||
errno = EINVALPART;
|
errno = EINVALPART;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_perror( "read failure @ sector %d\n", fd->startSector );
|
ntfs_log_perror( "read failure @ sector %d\n", fd->startSector );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -133,7 +142,8 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
|||||||
fd->ino = le64_to_cpu( boot.volume_serial_number );
|
fd->ino = le64_to_cpu( boot.volume_serial_number );
|
||||||
|
|
||||||
// Mark the device as read-only (if required)
|
// Mark the device as read-only (if required)
|
||||||
if (flags & O_RDONLY) {
|
if ( flags & O_RDONLY )
|
||||||
|
{
|
||||||
NDevSetReadOnly( dev );
|
NDevSetReadOnly( dev );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,13 +166,15 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device is actually open
|
// Check that the device is actually open
|
||||||
if (!NDevOpen(dev)) {
|
if ( !NDevOpen( dev ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "device is not open\n" );
|
ntfs_log_perror( "device is not open\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -173,7 +185,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
|||||||
NDevClearBlock( dev );
|
NDevClearBlock( dev );
|
||||||
|
|
||||||
// Flush the device (if dirty and not read-only)
|
// Flush the device (if dirty and not read-only)
|
||||||
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
if ( NDevDirty( dev ) && !NDevReadOnly( dev ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "device is dirty, will now sync\n" );
|
ntfs_log_debug( "device is dirty, will now sync\n" );
|
||||||
|
|
||||||
// ...?
|
// ...?
|
||||||
@ -184,7 +197,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flush and destroy the cache (if required)
|
// Flush and destroy the cache (if required)
|
||||||
if (fd->cache) {
|
if ( fd->cache )
|
||||||
|
{
|
||||||
_NTFS_cache_flush( fd->cache );
|
_NTFS_cache_flush( fd->cache );
|
||||||
_NTFS_cache_destructor( fd->cache );
|
_NTFS_cache_destructor( fd->cache );
|
||||||
}
|
}
|
||||||
@ -211,13 +225,15 @@ static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int wh
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the current position on the device (in bytes)
|
// Set the current position on the device (in bytes)
|
||||||
switch(whence) {
|
switch ( whence )
|
||||||
|
{
|
||||||
case SEEK_SET: fd->pos = MIN( MAX( offset, 0 ), fd->len ); break;
|
case SEEK_SET: fd->pos = MIN( MAX( offset, 0 ), fd->len ); break;
|
||||||
case SEEK_CUR: fd->pos = MIN( MAX( fd->pos + offset, 0 ), fd->len ); break;
|
case SEEK_CUR: fd->pos = MIN( MAX( fd->pos + offset, 0 ), fd->len ); break;
|
||||||
case SEEK_END: fd->pos = MIN( MAX( fd->len + offset, 0 ), fd->len ); break;
|
case SEEK_END: fd->pos = MIN( MAX( fd->len + offset, 0 ), fd->len ); break;
|
||||||
@ -267,14 +283,16 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if (!interface) {
|
if ( !interface )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -294,20 +312,24 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
u8 *buffer = NULL;
|
u8 *buffer = NULL;
|
||||||
|
|
||||||
// Determine the range of sectors required for this read
|
// Determine the range of sectors required for this read
|
||||||
if (offset > 0) {
|
if ( offset > 0 )
|
||||||
|
{
|
||||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||||
}
|
}
|
||||||
if (buffer_offset+count > fd->sectorSize) {
|
if ( buffer_offset + count > fd->sectorSize )
|
||||||
|
{
|
||||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
||||||
|
|
||||||
if((buffer_offset == 0) && (count % fd->sectorSize == 0)) {
|
if ( ( buffer_offset == 0 ) && ( count % fd->sectorSize == 0 ) )
|
||||||
|
{
|
||||||
|
|
||||||
// Read from the device
|
// Read from the device
|
||||||
ntfs_log_trace( "direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_log_trace( "direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buf ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_log_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -320,7 +342,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
|
|
||||||
// Allocate a buffer to hold the read data
|
// Allocate a buffer to hold the read data
|
||||||
buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize );
|
buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize );
|
||||||
if (!buffer) {
|
if ( !buffer )
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -328,7 +351,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
// Read from the device
|
// Read from the device
|
||||||
ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||||
ntfs_log_trace( "count: %d sec_count:%d fd->sectorSize: %d )\n", ( u32 )count, ( u32 )sec_count, ( u32 )fd->sectorSize );
|
ntfs_log_trace( "count: %d sec_count:%d fd->sectorSize: %d )\n", ( u32 )count, ( u32 )sec_count, ( u32 )fd->sectorSize );
|
||||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
|
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buffer ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||||
ntfs_free( buffer );
|
ntfs_free( buffer );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -353,25 +377,29 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if (!interface) {
|
if ( !interface )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device can be written to
|
// Check that the device can be written to
|
||||||
if (NDevReadOnly(dev)) {
|
if ( NDevReadOnly( dev ) )
|
||||||
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count < 0 || offset < 0) {
|
if ( count < 0 || offset < 0 )
|
||||||
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -385,10 +413,12 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
u8 *buffer = NULL;
|
u8 *buffer = NULL;
|
||||||
|
|
||||||
// Determine the range of sectors required for this write
|
// Determine the range of sectors required for this write
|
||||||
if (offset > 0) {
|
if ( offset > 0 )
|
||||||
|
{
|
||||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||||
}
|
}
|
||||||
if ((buffer_offset+count) > fd->sectorSize) {
|
if ( ( buffer_offset + count ) > fd->sectorSize )
|
||||||
|
{
|
||||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +427,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
{
|
{
|
||||||
// Write to the device
|
// Write to the device
|
||||||
ntfs_log_trace( "direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_log_trace( "direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
|
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buf ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_log_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -408,7 +439,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
{
|
{
|
||||||
// Allocate a buffer to hold the write data
|
// Allocate a buffer to hold the write data
|
||||||
buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize );
|
buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize );
|
||||||
if (!buffer) {
|
if ( !buffer )
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -417,7 +449,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
// we just read in the buffer edges where the data overlaps with the rest of the disc
|
// we just read in the buffer edges where the data overlaps with the rest of the disc
|
||||||
if ( buffer_offset != 0 )
|
if ( buffer_offset != 0 )
|
||||||
{
|
{
|
||||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, 1, buffer ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start );
|
ntfs_log_perror( "read failure @ sector %d\n", sec_start );
|
||||||
ntfs_free( buffer );
|
ntfs_free( buffer );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -426,7 +459,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
}
|
}
|
||||||
if ( ( buffer_offset + count ) % fd->sectorSize != 0 )
|
if ( ( buffer_offset + count ) % fd->sectorSize != 0 )
|
||||||
{
|
{
|
||||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) {
|
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start + sec_count - 1, 1, buffer + ( ( sec_count - 1 ) * fd->sectorSize ) ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 );
|
ntfs_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 );
|
||||||
ntfs_free( buffer );
|
ntfs_free( buffer );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -439,7 +473,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
|
|
||||||
// Write to the device
|
// Write to the device
|
||||||
ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buffer ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start );
|
ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start );
|
||||||
ntfs_free( buffer );
|
ntfs_free( buffer );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -460,7 +495,8 @@ static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sect
|
|||||||
{
|
{
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -477,7 +513,8 @@ static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sec
|
|||||||
{
|
{
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -500,7 +537,8 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
|||||||
ntfs_log_trace( "dev %p\n", dev );
|
ntfs_log_trace( "dev %p\n", dev );
|
||||||
|
|
||||||
// Check that the device can be written to
|
// Check that the device can be written to
|
||||||
if (NDevReadOnly(dev)) {
|
if ( NDevReadOnly( dev ) )
|
||||||
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -509,8 +547,10 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
|||||||
NDevClearDirty( dev );
|
NDevClearDirty( dev );
|
||||||
|
|
||||||
// Flush any sectors in the disc cache (if required)
|
// Flush any sectors in the disc cache (if required)
|
||||||
if (fd->cache) {
|
if ( fd->cache )
|
||||||
if (!_NTFS_cache_flush(fd->cache)) {
|
{
|
||||||
|
if ( !_NTFS_cache_flush( fd->cache ) )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -528,7 +568,8 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -565,17 +606,20 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD( dev );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out which i/o control was requested
|
// Figure out which i/o control was requested
|
||||||
switch (request) {
|
switch ( request )
|
||||||
|
{
|
||||||
|
|
||||||
// Get block device size (sectors)
|
// Get block device size (sectors)
|
||||||
#if defined(BLKGETSIZE)
|
#if defined(BLKGETSIZE)
|
||||||
case BLKGETSIZE: {
|
case BLKGETSIZE:
|
||||||
|
{
|
||||||
*( u32* )argp = fd->sectorCount;
|
*( u32* )argp = fd->sectorCount;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -583,7 +627,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
|
|
||||||
// Get block device size (bytes)
|
// Get block device size (bytes)
|
||||||
#if defined(BLKGETSIZE64)
|
#if defined(BLKGETSIZE64)
|
||||||
case BLKGETSIZE64: {
|
case BLKGETSIZE64:
|
||||||
|
{
|
||||||
*( u64* )argp = ( fd->sectorCount * fd->sectorSize );
|
*( u64* )argp = ( fd->sectorCount * fd->sectorSize );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -591,7 +636,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
|
|
||||||
// Get hard drive geometry
|
// Get hard drive geometry
|
||||||
#if defined(HDIO_GETGEO)
|
#if defined(HDIO_GETGEO)
|
||||||
case HDIO_GETGEO: {
|
case HDIO_GETGEO:
|
||||||
|
{
|
||||||
struct hd_geometry *geo = ( struct hd_geometry* )argp;
|
struct hd_geometry *geo = ( struct hd_geometry* )argp;
|
||||||
geo->sectors = 0;
|
geo->sectors = 0;
|
||||||
geo->heads = 0;
|
geo->heads = 0;
|
||||||
@ -603,7 +649,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
|
|
||||||
// Get block device sector size (bytes)
|
// Get block device sector size (bytes)
|
||||||
#if defined(BLKSSZGET)
|
#if defined(BLKSSZGET)
|
||||||
case BLKSSZGET: {
|
case BLKSSZGET:
|
||||||
|
{
|
||||||
*( int* )argp = fd->sectorSize;
|
*( int* )argp = fd->sectorSize;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -611,7 +658,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
|
|
||||||
// Set block device block size (bytes)
|
// Set block device block size (bytes)
|
||||||
#if defined(BLKBSZSET)
|
#if defined(BLKBSZSET)
|
||||||
case BLKBSZSET: {
|
case BLKBSZSET:
|
||||||
|
{
|
||||||
int sectorSize = *( int* )argp;
|
int sectorSize = *( int* )argp;
|
||||||
fd->sectorSize = sectorSize;
|
fd->sectorSize = sectorSize;
|
||||||
return 0;
|
return 0;
|
||||||
@ -619,7 +667,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Unimplemented ioctrl
|
// Unimplemented ioctrl
|
||||||
default: {
|
default:
|
||||||
|
{
|
||||||
ntfs_log_perror( "Unimplemented ioctrl %i\n", request );
|
ntfs_log_perror( "Unimplemented ioctrl %i\n", request );
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
return -1;
|
return -1;
|
||||||
@ -633,7 +682,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
/**
|
/**
|
||||||
* Device operations for working with gekko style devices and files.
|
* Device operations for working with gekko style devices and files.
|
||||||
*/
|
*/
|
||||||
struct ntfs_device_operations ntfs_device_gekko_io_ops = {
|
struct ntfs_device_operations ntfs_device_gekko_io_ops =
|
||||||
|
{
|
||||||
.open = ntfs_device_gekko_io_open,
|
.open = ntfs_device_gekko_io_open,
|
||||||
.close = ntfs_device_gekko_io_close,
|
.close = ntfs_device_gekko_io_close,
|
||||||
.seek = ntfs_device_gekko_io_seek,
|
.seek = ntfs_device_gekko_io_seek,
|
||||||
|
@ -33,7 +33,8 @@
|
|||||||
/**
|
/**
|
||||||
* gekko_fd - Gekko device driver descriptor
|
* gekko_fd - Gekko device driver descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct _gekko_fd {
|
typedef struct _gekko_fd
|
||||||
|
{
|
||||||
const DISC_INTERFACE* interface; /* Device disc interface */
|
const DISC_INTERFACE* interface; /* Device disc interface */
|
||||||
sec_t startSector; /* LBA of partition start */
|
sec_t startSector; /* LBA of partition start */
|
||||||
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
||||||
|
@ -88,7 +88,8 @@ static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib)
|
|||||||
|
|
||||||
ret = ntfs_attr_mst_pwrite( icx->ia_na, ntfs_ib_vcn_to_pos( icx, vcn ),
|
ret = ntfs_attr_mst_pwrite( icx->ia_na, ntfs_ib_vcn_to_pos( icx, vcn ),
|
||||||
1, icx->block_size, ib );
|
1, icx->block_size, ib );
|
||||||
if (ret != 1) {
|
if ( ret != 1 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to write index block %lld, inode %llu",
|
ntfs_log_perror( "Failed to write index block %lld, inode %llu",
|
||||||
( long long )vcn, ( unsigned long long )icx->ni->mft_no );
|
( long long )vcn, ( unsigned long long )icx->ni->mft_no );
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
@ -123,7 +124,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -131,7 +133,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
|||||||
ni = ni->base_ni;
|
ni = ni->base_ni;
|
||||||
icx = ntfs_calloc( sizeof( ntfs_index_context ) );
|
icx = ntfs_calloc( sizeof( ntfs_index_context ) );
|
||||||
if ( icx )
|
if ( icx )
|
||||||
*icx = (ntfs_index_context) {
|
*icx = ( ntfs_index_context )
|
||||||
|
{
|
||||||
.ni = ni,
|
.ni = ni,
|
||||||
.name = name,
|
.name = name,
|
||||||
.name_len = name_len,
|
.name_len = name_len,
|
||||||
@ -149,8 +152,10 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
|
|||||||
if ( icx->actx )
|
if ( icx->actx )
|
||||||
ntfs_attr_put_search_ctx( icx->actx );
|
ntfs_attr_put_search_ctx( icx->actx );
|
||||||
|
|
||||||
if (!icx->is_in_root) {
|
if ( !icx->is_in_root )
|
||||||
if (icx->ib_dirty) {
|
{
|
||||||
|
if ( icx->ib_dirty )
|
||||||
|
{
|
||||||
/* FIXME: Error handling!!! */
|
/* FIXME: Error handling!!! */
|
||||||
ntfs_ib_write( icx, icx->ib );
|
ntfs_ib_write( icx, icx->ib );
|
||||||
}
|
}
|
||||||
@ -184,7 +189,8 @@ void ntfs_index_ctx_reinit(ntfs_index_context *icx)
|
|||||||
|
|
||||||
ntfs_index_ctx_free( icx );
|
ntfs_index_ctx_free( icx );
|
||||||
|
|
||||||
*icx = (ntfs_index_context) {
|
*icx = ( ntfs_index_context )
|
||||||
|
{
|
||||||
.ni = icx->ni,
|
.ni = icx->ni,
|
||||||
.name = icx->name,
|
.name = icx->name,
|
||||||
.name_len = icx->name_len,
|
.name_len = icx->name_len,
|
||||||
@ -261,7 +267,8 @@ static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie)
|
|||||||
|
|
||||||
tmp = ntfs_ie_get_first( ih );
|
tmp = ntfs_ie_get_first( ih );
|
||||||
|
|
||||||
while (tmp != ie) {
|
while ( tmp != ie )
|
||||||
|
{
|
||||||
ie_prev = tmp;
|
ie_prev = tmp;
|
||||||
tmp = ntfs_ie_get_next( tmp );
|
tmp = ntfs_ie_get_next( tmp );
|
||||||
}
|
}
|
||||||
@ -293,7 +300,8 @@ void ntfs_ih_filename_dump(INDEX_HEADER *ih)
|
|||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
ie = ntfs_ie_get_first( ih );
|
ie = ntfs_ie_get_first( ih );
|
||||||
while (!ntfs_ie_end(ie)) {
|
while ( !ntfs_ie_end( ie ) )
|
||||||
|
{
|
||||||
ntfs_ie_filename_dump( ie );
|
ntfs_ie_filename_dump( ie );
|
||||||
ie = ntfs_ie_get_next( ie );
|
ie = ntfs_ie_get_next( ie );
|
||||||
}
|
}
|
||||||
@ -380,7 +388,8 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
|
|||||||
size -= sizeof( VCN );
|
size -= sizeof( VCN );
|
||||||
|
|
||||||
dup = ntfs_malloc( size );
|
dup = ntfs_malloc( size );
|
||||||
if (dup) {
|
if ( dup )
|
||||||
|
{
|
||||||
memcpy( dup, ie, size );
|
memcpy( dup, ie, size );
|
||||||
dup->ie_flags &= ~INDEX_ENTRY_NODE;
|
dup->ie_flags &= ~INDEX_ENTRY_NODE;
|
||||||
dup->length = cpu_to_le16( size );
|
dup->length = cpu_to_le16( size );
|
||||||
@ -394,7 +403,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
if (!ntfs_is_indx_record(ib->magic)) {
|
if ( !ntfs_is_indx_record( ib->magic ) )
|
||||||
|
{
|
||||||
|
|
||||||
ntfs_log_error( "Corrupt index block signature: vcn %lld inode "
|
ntfs_log_error( "Corrupt index block signature: vcn %lld inode "
|
||||||
"%llu\n", ( long long )vcn,
|
"%llu\n", ( long long )vcn,
|
||||||
@ -402,7 +412,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
|
if ( sle64_to_cpu( ib->index_block_vcn ) != vcn )
|
||||||
|
{
|
||||||
|
|
||||||
ntfs_log_error( "Corrupt index block: VCN (%lld) is different "
|
ntfs_log_error( "Corrupt index block: VCN (%lld) is different "
|
||||||
"from expected VCN (%lld) in inode %llu\n",
|
"from expected VCN (%lld) in inode %llu\n",
|
||||||
@ -412,7 +423,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ib_size != icx->block_size) {
|
if ( ib_size != icx->block_size )
|
||||||
|
{
|
||||||
|
|
||||||
ntfs_log_error( "Corrupt index block : VCN (%lld) of inode %llu "
|
ntfs_log_error( "Corrupt index block : VCN (%lld) of inode %llu "
|
||||||
"has a size (%u) differing from the index "
|
"has a size (%u) differing from the index "
|
||||||
@ -437,13 +449,15 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ( ntfs_attr_lookup( AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE,
|
if ( ntfs_attr_lookup( AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE,
|
||||||
0, NULL, 0, *ctx)) {
|
0, NULL, 0, *ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to lookup $INDEX_ROOT" );
|
ntfs_log_perror( "Failed to lookup $INDEX_ROOT" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
a = ( *ctx )->attr;
|
a = ( *ctx )->attr;
|
||||||
if (a->non_resident) {
|
if ( a->non_resident )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "Non-resident $INDEX_ROOT detected" );
|
ntfs_log_perror( "Non-resident $INDEX_ROOT detected" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -451,7 +465,8 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
|
|||||||
|
|
||||||
ir = ( INDEX_ROOT * )( ( char * )a + le16_to_cpu( a->value_offset ) );
|
ir = ( INDEX_ROOT * )( ( char * )a + le16_to_cpu( a->value_offset ) );
|
||||||
err_out:
|
err_out:
|
||||||
if (!ir) {
|
if ( !ir )
|
||||||
|
{
|
||||||
ntfs_attr_put_search_ctx( *ctx );
|
ntfs_attr_put_search_ctx( *ctx );
|
||||||
*ctx = NULL;
|
*ctx = NULL;
|
||||||
}
|
}
|
||||||
@ -497,10 +512,12 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
|
|||||||
* Loop until we exceed valid memory (corruption case) or until we
|
* Loop until we exceed valid memory (corruption case) or until we
|
||||||
* reach the last entry.
|
* reach the last entry.
|
||||||
*/
|
*/
|
||||||
for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) {
|
for ( ie = ntfs_ie_get_first( ih ); ; ie = ntfs_ie_get_next( ie ) )
|
||||||
|
{
|
||||||
/* Bounds checks. */
|
/* Bounds checks. */
|
||||||
if ( ( u8 * )ie + sizeof( INDEX_ENTRY_HEADER ) > index_end ||
|
if ( ( u8 * )ie + sizeof( INDEX_ENTRY_HEADER ) > index_end ||
|
||||||
(u8 *)ie + le16_to_cpu(ie->length) > index_end) {
|
( u8 * )ie + le16_to_cpu( ie->length ) > index_end )
|
||||||
|
{
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
ntfs_log_error( "Index entry out of bounds in inode "
|
ntfs_log_error( "Index entry out of bounds in inode "
|
||||||
"%llu.\n",
|
"%llu.\n",
|
||||||
@ -517,14 +534,16 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
|
|||||||
* Not a perfect match, need to do full blown collation so we
|
* Not a perfect match, need to do full blown collation so we
|
||||||
* know which way in the B+tree we have to go.
|
* know which way in the B+tree we have to go.
|
||||||
*/
|
*/
|
||||||
if (!icx->collate) {
|
if ( !icx->collate )
|
||||||
|
{
|
||||||
ntfs_log_error( "Collation function not defined\n" );
|
ntfs_log_error( "Collation function not defined\n" );
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
rc = icx->collate( icx->ni->vol, key, key_len,
|
rc = icx->collate( icx->ni->vol, key, key_len,
|
||||||
&ie->key, le16_to_cpu( ie->key_length ) );
|
&ie->key, le16_to_cpu( ie->key_length ) );
|
||||||
if (rc == NTFS_COLLATION_ERROR) {
|
if ( rc == NTFS_COLLATION_ERROR )
|
||||||
|
{
|
||||||
ntfs_log_error( "Collation error. Perhaps a filename "
|
ntfs_log_error( "Collation error. Perhaps a filename "
|
||||||
"contains invalid characters?\n" );
|
"contains invalid characters?\n" );
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
@ -538,7 +557,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
|
|||||||
if ( rc == -1 )
|
if ( rc == -1 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!rc) {
|
if ( !rc )
|
||||||
|
{
|
||||||
*ie_out = ie;
|
*ie_out = ie;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
icx->parent_pos[icx->pindex] = item;
|
icx->parent_pos[icx->pindex] = item;
|
||||||
@ -552,7 +572,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
|
|||||||
* presence of a child node and if not present return with errno ENOENT,
|
* presence of a child node and if not present return with errno ENOENT,
|
||||||
* otherwise we will keep searching in another index block.
|
* otherwise we will keep searching in another index block.
|
||||||
*/
|
*/
|
||||||
if (!(ie->ie_flags & INDEX_ENTRY_NODE)) {
|
if ( !( ie->ie_flags & INDEX_ENTRY_NODE ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Index entry wasn't found.\n" );
|
ntfs_log_debug( "Index entry wasn't found.\n" );
|
||||||
*ie_out = ie;
|
*ie_out = ie;
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
@ -561,7 +582,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
|
|||||||
|
|
||||||
/* Get the starting vcn of the index_block holding the child node. */
|
/* Get the starting vcn of the index_block holding the child node. */
|
||||||
*vcn = ntfs_ie_get_vcn( ie );
|
*vcn = ntfs_ie_get_vcn( ie );
|
||||||
if (*vcn < 0) {
|
if ( *vcn < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "Negative vcn in inode %llu",
|
ntfs_log_perror( "Negative vcn in inode %llu",
|
||||||
( unsigned long long )icx->ni->mft_no );
|
( unsigned long long )icx->ni->mft_no );
|
||||||
@ -579,7 +601,8 @@ static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni)
|
|||||||
ntfs_attr *na;
|
ntfs_attr *na;
|
||||||
|
|
||||||
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len );
|
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to open index allocation of inode "
|
ntfs_log_perror( "Failed to open index allocation of inode "
|
||||||
"%llu", ( unsigned long long )ni->mft_no );
|
"%llu", ( unsigned long long )ni->mft_no );
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -597,7 +620,8 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
|
|||||||
pos = ntfs_ib_vcn_to_pos( icx, vcn );
|
pos = ntfs_ib_vcn_to_pos( icx, vcn );
|
||||||
|
|
||||||
ret = ntfs_attr_mst_pread( icx->ia_na, pos, 1, icx->block_size, ( u8 * )dst );
|
ret = ntfs_attr_mst_pread( icx->ia_na, pos, 1, icx->block_size, ( u8 * )dst );
|
||||||
if (ret != 1) {
|
if ( ret != 1 )
|
||||||
|
{
|
||||||
if ( ret == -1 )
|
if ( ret == -1 )
|
||||||
ntfs_log_perror( "Failed to read index block" );
|
ntfs_log_perror( "Failed to read index block" );
|
||||||
else
|
else
|
||||||
@ -615,7 +639,8 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
|
|||||||
static int ntfs_icx_parent_inc( ntfs_index_context *icx )
|
static int ntfs_icx_parent_inc( ntfs_index_context *icx )
|
||||||
{
|
{
|
||||||
icx->pindex++;
|
icx->pindex++;
|
||||||
if (icx->pindex >= MAX_PARENT_VCN) {
|
if ( icx->pindex >= MAX_PARENT_VCN )
|
||||||
|
{
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
ntfs_log_perror( "Index is over %d level deep", MAX_PARENT_VCN );
|
ntfs_log_perror( "Index is over %d level deep", MAX_PARENT_VCN );
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
@ -626,7 +651,8 @@ static int ntfs_icx_parent_inc(ntfs_index_context *icx)
|
|||||||
static int ntfs_icx_parent_dec( ntfs_index_context *icx )
|
static int ntfs_icx_parent_dec( ntfs_index_context *icx )
|
||||||
{
|
{
|
||||||
icx->pindex--;
|
icx->pindex--;
|
||||||
if (icx->pindex < 0) {
|
if ( icx->pindex < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "Corrupt index pointer (%d)", icx->pindex );
|
ntfs_log_perror( "Corrupt index pointer (%d)", icx->pindex );
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
@ -677,21 +703,24 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
if (!key || key_len <= 0) {
|
if ( !key || key_len <= 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "key: %p key_len: %d", key, key_len );
|
ntfs_log_perror( "key: %p key_len: %d", key, key_len );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ir = ntfs_ir_lookup( ni, icx->name, icx->name_len, &icx->actx );
|
ir = ntfs_ir_lookup( ni, icx->name, icx->name_len, &icx->actx );
|
||||||
if (!ir) {
|
if ( !ir )
|
||||||
|
{
|
||||||
if ( errno == ENOENT )
|
if ( errno == ENOENT )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
icx->block_size = le32_to_cpu( ir->index_block_size );
|
icx->block_size = le32_to_cpu( ir->index_block_size );
|
||||||
if (icx->block_size < NTFS_BLOCK_SIZE) {
|
if ( icx->block_size < NTFS_BLOCK_SIZE )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "Index block size (%d) is smaller than the "
|
ntfs_log_perror( "Index block size (%d) is smaller than the "
|
||||||
"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE );
|
"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE );
|
||||||
@ -704,7 +733,8 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
|
|||||||
icx->vcn_size_bits = ni->vol->sector_size_bits;
|
icx->vcn_size_bits = ni->vol->sector_size_bits;
|
||||||
/* get the appropriate collation function */
|
/* get the appropriate collation function */
|
||||||
icx->collate = ntfs_get_collate_function( ir->collation_rule );
|
icx->collate = ntfs_get_collate_function( ir->collation_rule );
|
||||||
if (!icx->collate) {
|
if ( !icx->collate )
|
||||||
|
{
|
||||||
err = errno = EOPNOTSUPP;
|
err = errno = EOPNOTSUPP;
|
||||||
ntfs_log_perror( "Unknown collation rule 0x%x",
|
ntfs_log_perror( "Unknown collation rule 0x%x",
|
||||||
( unsigned )le32_to_cpu( ir->collation_rule ) );
|
( unsigned )le32_to_cpu( ir->collation_rule ) );
|
||||||
@ -717,14 +747,16 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
|
|||||||
* within the index block.
|
* within the index block.
|
||||||
*/
|
*/
|
||||||
ret = ntfs_ie_lookup( key, key_len, icx, &ir->index, &vcn, &ie );
|
ret = ntfs_ie_lookup( key, key_len, icx, &ir->index, &vcn, &ie );
|
||||||
if (ret == STATUS_ERROR) {
|
if ( ret == STATUS_ERROR )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
icx->ir = ir;
|
icx->ir = ir;
|
||||||
|
|
||||||
if (ret != STATUS_KEEP_SEARCHING) {
|
if ( ret != STATUS_KEEP_SEARCHING )
|
||||||
|
{
|
||||||
/* STATUS_OK or STATUS_NOT_FOUND */
|
/* STATUS_OK or STATUS_NOT_FOUND */
|
||||||
err = errno;
|
err = errno;
|
||||||
icx->is_in_root = TRUE;
|
icx->is_in_root = TRUE;
|
||||||
@ -739,7 +771,8 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
ib = ntfs_malloc( icx->block_size );
|
ib = ntfs_malloc( icx->block_size );
|
||||||
if (!ib) {
|
if ( !ib )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -747,7 +780,8 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
|
|||||||
descend_into_child_node:
|
descend_into_child_node:
|
||||||
|
|
||||||
icx->parent_vcn[icx->pindex] = old_vcn;
|
icx->parent_vcn[icx->pindex] = old_vcn;
|
||||||
if (ntfs_icx_parent_inc(icx)) {
|
if ( ntfs_icx_parent_inc( icx ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -759,7 +793,8 @@ descend_into_child_node:
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
ret = ntfs_ie_lookup( key, key_len, icx, &ib->index, &vcn, &ie );
|
ret = ntfs_ie_lookup( key, key_len, icx, &ib->index, &vcn, &ie );
|
||||||
if (ret != STATUS_KEEP_SEARCHING) {
|
if ( ret != STATUS_KEEP_SEARCHING )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
if ( ret == STATUS_ERROR )
|
if ( ret == STATUS_ERROR )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -771,7 +806,8 @@ descend_into_child_node:
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) {
|
if ( ( ib->index.ih_flags & NODE_MASK ) == LEAF_NODE )
|
||||||
|
{
|
||||||
ntfs_log_error( "Index entry with child node found in a leaf "
|
ntfs_log_error( "Index entry with child node found in a leaf "
|
||||||
"node in inode 0x%llx.\n",
|
"node in inode 0x%llx.\n",
|
||||||
( unsigned long long )ni->mft_no );
|
( unsigned long long )ni->mft_no );
|
||||||
@ -790,7 +826,8 @@ done:
|
|||||||
icx->data = ( u8 * )ie + offsetof( INDEX_ENTRY, key );
|
icx->data = ( u8 * )ie + offsetof( INDEX_ENTRY, key );
|
||||||
icx->data_len = le16_to_cpu( ie->key_length );
|
icx->data_len = le16_to_cpu( ie->key_length );
|
||||||
ntfs_log_trace( "Done.\n" );
|
ntfs_log_trace( "Done.\n" );
|
||||||
if (err) {
|
if ( err )
|
||||||
|
{
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -843,7 +880,8 @@ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih)
|
|||||||
ie = ie_start = ntfs_ie_get_first( ih );
|
ie = ie_start = ntfs_ie_get_first( ih );
|
||||||
ie_end = ( u8 * )ntfs_ie_get_end( ih );
|
ie_end = ( u8 * )ntfs_ie_get_end( ih );
|
||||||
|
|
||||||
while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) {
|
while ( ( u8 * )ie < ie_end && !ntfs_ie_end( ie ) )
|
||||||
|
{
|
||||||
ie = ntfs_ie_get_next( ie );
|
ie = ntfs_ie_get_next( ie );
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -883,7 +921,8 @@ static int ntfs_ibm_add(ntfs_index_context *icx)
|
|||||||
*/
|
*/
|
||||||
memset( bmp, 0, sizeof( bmp ) );
|
memset( bmp, 0, sizeof( bmp ) );
|
||||||
if ( ntfs_attr_add( icx->ni, AT_BITMAP, icx->name, icx->name_len,
|
if ( ntfs_attr_add( icx->ni, AT_BITMAP, icx->name, icx->name_len,
|
||||||
bmp, sizeof(bmp))) {
|
bmp, sizeof( bmp ) ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to add AT_BITMAP" );
|
ntfs_log_perror( "Failed to add AT_BITMAP" );
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
@ -903,21 +942,26 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
|
|||||||
ntfs_log_trace( "%s vcn: %lld\n", set ? "set" : "clear", ( long long )vcn );
|
ntfs_log_trace( "%s vcn: %lld\n", set ? "set" : "clear", ( long long )vcn );
|
||||||
|
|
||||||
na = ntfs_attr_open( icx->ni, AT_BITMAP, icx->name, icx->name_len );
|
na = ntfs_attr_open( icx->ni, AT_BITMAP, icx->name, icx->name_len );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to open $BITMAP attribute" );
|
ntfs_log_perror( "Failed to open $BITMAP attribute" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set) {
|
if ( set )
|
||||||
if (na->data_size < bpos + 1) {
|
{
|
||||||
if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) {
|
if ( na->data_size < bpos + 1 )
|
||||||
|
{
|
||||||
|
if ( ntfs_attr_truncate( na, ( na->data_size + 8 ) & ~7 ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to truncate AT_BITMAP" );
|
ntfs_log_perror( "Failed to truncate AT_BITMAP" );
|
||||||
goto err_na;
|
goto err_na;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) {
|
if ( ntfs_attr_pread( na, bpos, 1, &byte ) != 1 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to read $BITMAP" );
|
ntfs_log_perror( "Failed to read $BITMAP" );
|
||||||
goto err_na;
|
goto err_na;
|
||||||
}
|
}
|
||||||
@ -927,7 +971,8 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
|
|||||||
else
|
else
|
||||||
byte &= ~bit;
|
byte &= ~bit;
|
||||||
|
|
||||||
if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) {
|
if ( ntfs_attr_pwrite( na, bpos, 1, &byte ) != 1 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to write $Bitmap" );
|
ntfs_log_perror( "Failed to write $Bitmap" );
|
||||||
goto err_na;
|
goto err_na;
|
||||||
}
|
}
|
||||||
@ -962,13 +1007,16 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx)
|
|||||||
if ( !bm )
|
if ( !bm )
|
||||||
return ( VCN ) - 1;
|
return ( VCN ) - 1;
|
||||||
|
|
||||||
for (byte = 0; byte < size; byte++) {
|
for ( byte = 0; byte < size; byte++ )
|
||||||
|
{
|
||||||
|
|
||||||
if ( bm[byte] == 255 )
|
if ( bm[byte] == 255 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (bit = 0; bit < 8; bit++) {
|
for ( bit = 0; bit < 8; bit++ )
|
||||||
if (!(bm[byte] & (1 << bit))) {
|
{
|
||||||
|
if ( !( bm[byte] & ( 1 << bit ) ) )
|
||||||
|
{
|
||||||
vcn = ntfs_ibm_pos_to_vcn( icx, byte * 8 + bit );
|
vcn = ntfs_ibm_pos_to_vcn( icx, byte * 8 + bit );
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1030,7 +1078,8 @@ static void ntfs_ir_nill(INDEX_ROOT *ir)
|
|||||||
/*
|
/*
|
||||||
* Move the index root termination entry forward
|
* Move the index root termination entry forward
|
||||||
*/
|
*/
|
||||||
if ((char *)ie_last > ies_start) {
|
if ( ( char * )ie_last > ies_start )
|
||||||
|
{
|
||||||
memmove( ies_start, ( char * )ie_last, le16_to_cpu( ie_last->length ) );
|
memmove( ies_start, ( char * )ie_last, le16_to_cpu( ie_last->length ) );
|
||||||
ie_last = ( INDEX_ENTRY * )ies_start;
|
ie_last = ( INDEX_ENTRY * )ies_start;
|
||||||
}
|
}
|
||||||
@ -1098,10 +1147,12 @@ static int ntfs_ia_add(ntfs_index_context *icx)
|
|||||||
if ( ntfs_ibm_add( icx ) )
|
if ( ntfs_ibm_add( icx ) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) {
|
if ( !ntfs_attr_exist( icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len ) )
|
||||||
|
{
|
||||||
|
|
||||||
if ( ntfs_attr_add( icx->ni, AT_INDEX_ALLOCATION, icx->name,
|
if ( ntfs_attr_add( icx->ni, AT_INDEX_ALLOCATION, icx->name,
|
||||||
icx->name_len, NULL, 0)) {
|
icx->name_len, NULL, 0 ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to add AT_INDEX_ALLOCATION" );
|
ntfs_log_perror( "Failed to add AT_INDEX_ALLOCATION" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1142,7 +1193,8 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
|
|||||||
goto clear_bmp;
|
goto clear_bmp;
|
||||||
|
|
||||||
ib = ntfs_ir_to_ib( ir, new_ib_vcn );
|
ib = ntfs_ir_to_ib( ir, new_ib_vcn );
|
||||||
if (ib == NULL) {
|
if ( ib == NULL )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to move index root to index block" );
|
ntfs_log_perror( "Failed to move index root to index block" );
|
||||||
goto clear_bmp;
|
goto clear_bmp;
|
||||||
}
|
}
|
||||||
@ -1200,7 +1252,8 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
|
|||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
na = ntfs_attr_open( icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len );
|
na = ntfs_attr_open( icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to open INDEX_ROOT" );
|
ntfs_log_perror( "Failed to open INDEX_ROOT" );
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
@ -1209,7 +1262,8 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
|
|||||||
* INDEX_BLOCK, so ENOSPC isn't a real error.
|
* INDEX_BLOCK, so ENOSPC isn't a real error.
|
||||||
*/
|
*/
|
||||||
ret = ntfs_attr_truncate( na, data_size + offsetof( INDEX_ROOT, index ) );
|
ret = ntfs_attr_truncate( na, data_size + offsetof( INDEX_ROOT, index ) );
|
||||||
if (ret == STATUS_OK) {
|
if ( ret == STATUS_OK )
|
||||||
|
{
|
||||||
|
|
||||||
icx->ir = ntfs_ir_lookup2( icx->ni, icx->name, icx->name_len );
|
icx->ir = ntfs_ir_lookup2( icx->ni, icx->name, icx->name_len );
|
||||||
if ( !icx->ir )
|
if ( !icx->ir )
|
||||||
@ -1217,7 +1271,8 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
|
|||||||
|
|
||||||
icx->ir->index.allocated_size = cpu_to_le32( data_size );
|
icx->ir->index.allocated_size = cpu_to_le32( data_size );
|
||||||
|
|
||||||
} else if (ret == STATUS_ERROR)
|
}
|
||||||
|
else if ( ret == STATUS_ERROR )
|
||||||
ntfs_log_perror( "Failed to truncate INDEX_ROOT" );
|
ntfs_log_perror( "Failed to truncate INDEX_ROOT" );
|
||||||
|
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
@ -1237,7 +1292,8 @@ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size)
|
|||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
ret = ntfs_ir_truncate( icx, data_size );
|
ret = ntfs_ir_truncate( icx, data_size );
|
||||||
if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) {
|
if ( ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT )
|
||||||
|
{
|
||||||
|
|
||||||
ret = ntfs_ir_reparent( icx );
|
ret = ntfs_ir_reparent( icx );
|
||||||
if ( ret == STATUS_OK )
|
if ( ret == STATUS_OK )
|
||||||
@ -1364,7 +1420,8 @@ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn)
|
|||||||
idx_size = le32_to_cpu( ib->index.index_length );
|
idx_size = le32_to_cpu( ib->index.index_length );
|
||||||
allocated_size = le32_to_cpu( ib->index.allocated_size );
|
allocated_size = le32_to_cpu( ib->index.allocated_size );
|
||||||
/* FIXME: sizeof(VCN) should be included only if ie has no VCN */
|
/* FIXME: sizeof(VCN) should be included only if ie has no VCN */
|
||||||
if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) {
|
if ( idx_size + le16_to_cpu( ie->length ) + sizeof( VCN ) > allocated_size )
|
||||||
|
{
|
||||||
err = ntfs_ib_split( icx, ib );
|
err = ntfs_ib_split( icx, ib );
|
||||||
if ( err == STATUS_OK )
|
if ( err == STATUS_OK )
|
||||||
err = STATUS_KEEP_SEARCHING;
|
err = STATUS_KEEP_SEARCHING;
|
||||||
@ -1405,7 +1462,8 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
|
|||||||
if ( new_vcn == -1 )
|
if ( new_vcn == -1 )
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
|
||||||
if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) {
|
if ( ntfs_ib_copy_tail( icx, ib, median, new_vcn ) )
|
||||||
|
{
|
||||||
ntfs_ibm_clear( icx, new_vcn );
|
ntfs_ibm_clear( icx, new_vcn );
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
@ -1415,7 +1473,8 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
|
|||||||
else
|
else
|
||||||
ret = ntfs_ib_insert( icx, median, new_vcn );
|
ret = ntfs_ib_insert( icx, median, new_vcn );
|
||||||
|
|
||||||
if (ret != STATUS_OK) {
|
if ( ret != STATUS_OK )
|
||||||
|
{
|
||||||
ntfs_ibm_clear( icx, new_vcn );
|
ntfs_ibm_clear( icx, new_vcn );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1441,14 +1500,17 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1) {
|
while ( 1 )
|
||||||
|
{
|
||||||
|
|
||||||
if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) {
|
if ( !ntfs_index_lookup( &ie->key, le16_to_cpu( ie->key_length ), icx ) )
|
||||||
|
{
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
ntfs_log_perror( "Index already have such entry" );
|
ntfs_log_perror( "Index already have such entry" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (errno != ENOENT) {
|
if ( errno != ENOENT )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to find place for new entry" );
|
ntfs_log_perror( "Failed to find place for new entry" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -1467,10 +1529,13 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
|
|||||||
ntfs_log_trace( "index block sizes: allocated: %d needed: %d\n",
|
ntfs_log_trace( "index block sizes: allocated: %d needed: %d\n",
|
||||||
allocated_size, new_size );
|
allocated_size, new_size );
|
||||||
|
|
||||||
if (icx->is_in_root) {
|
if ( icx->is_in_root )
|
||||||
|
{
|
||||||
if ( ntfs_ir_make_space( icx, new_size ) == STATUS_ERROR )
|
if ( ntfs_ir_make_space( icx, new_size ) == STATUS_ERROR )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( ntfs_ib_split( icx, icx->ib ) == STATUS_ERROR )
|
if ( ntfs_ib_split( icx, icx->ib ) == STATUS_ERROR )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -1504,7 +1569,8 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
if (!ni || !fn) {
|
if ( !ni || !fn )
|
||||||
|
{
|
||||||
ntfs_log_error( "Invalid arguments.\n" );
|
ntfs_log_error( "Invalid arguments.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -1552,8 +1618,7 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih,
|
|||||||
|
|
||||||
if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
|
if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
|
||||||
ntfs_inode_mark_dirty( icx->actx->ntfs_ino );
|
ntfs_inode_mark_dirty( icx->actx->ntfs_ino );
|
||||||
else
|
else if ( ntfs_ib_write( icx, ib ) )
|
||||||
if (ntfs_ib_write(icx, ib))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ntfs_index_ctx_reinit( icx );
|
ntfs_index_ctx_reinit( icx );
|
||||||
@ -1621,7 +1686,8 @@ static int ntfs_index_rm_leaf(ntfs_index_context *icx)
|
|||||||
|
|
||||||
if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
|
if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
|
||||||
parent_ih = &icx->ir->index;
|
parent_ih = &icx->ir->index;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
ib = ntfs_malloc( icx->block_size );
|
ib = ntfs_malloc( icx->block_size );
|
||||||
if ( !ib )
|
if ( !ib )
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
@ -1633,14 +1699,17 @@ static int ntfs_index_rm_leaf(ntfs_index_context *icx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ie = ntfs_ie_get_by_pos( parent_ih, ntfs_icx_parent_pos( icx ) );
|
ie = ntfs_ie_get_by_pos( parent_ih, ntfs_icx_parent_pos( icx ) );
|
||||||
if (!ntfs_ie_end(ie)) {
|
if ( !ntfs_ie_end( ie ) )
|
||||||
|
{
|
||||||
ret = ntfs_ih_takeout( icx, parent_ih, ie, ib );
|
ret = ntfs_ih_takeout( icx, parent_ih, ie, ib );
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntfs_ih_zero_entry(parent_ih)) {
|
if ( ntfs_ih_zero_entry( parent_ih ) )
|
||||||
|
{
|
||||||
|
|
||||||
if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) {
|
if ( ntfs_icx_parent_vcn( icx ) == VCN_INDEX_ROOT_PARENT )
|
||||||
|
{
|
||||||
ntfs_ir_leafify( icx, parent_ih );
|
ntfs_ir_leafify( icx, parent_ih );
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
@ -1670,7 +1739,8 @@ static int ntfs_index_rm_node(ntfs_index_context *icx)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
if (!icx->ia_na) {
|
if ( !icx->ia_na )
|
||||||
|
{
|
||||||
icx->ia_na = ntfs_ia_open( icx, icx->ni );
|
icx->ia_na = ntfs_ia_open( icx, icx->ni );
|
||||||
if ( !icx->ia_na )
|
if ( !icx->ia_na )
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
@ -1699,7 +1769,8 @@ descend:
|
|||||||
if ( ( ib->index.ih_flags & NODE_MASK ) == INDEX_NODE )
|
if ( ( ib->index.ih_flags & NODE_MASK ) == INDEX_NODE )
|
||||||
goto descend;
|
goto descend;
|
||||||
|
|
||||||
if (ntfs_ih_zero_entry(&ib->index)) {
|
if ( ntfs_ih_zero_entry( &ib->index ) )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Empty index block" );
|
ntfs_log_perror( "Empty index block" );
|
||||||
goto out;
|
goto out;
|
||||||
@ -1721,8 +1792,10 @@ descend:
|
|||||||
|
|
||||||
delta = le16_to_cpu( ie->length ) - le16_to_cpu( icx->entry->length );
|
delta = le16_to_cpu( ie->length ) - le16_to_cpu( icx->entry->length );
|
||||||
new_size = le32_to_cpu( ih->index_length ) + delta;
|
new_size = le32_to_cpu( ih->index_length ) + delta;
|
||||||
if (delta > 0) {
|
if ( delta > 0 )
|
||||||
if (icx->is_in_root) {
|
{
|
||||||
|
if ( icx->is_in_root )
|
||||||
|
{
|
||||||
ret = ntfs_ir_make_space( icx, new_size );
|
ret = ntfs_ir_make_space( icx, new_size );
|
||||||
if ( ret != STATUS_OK )
|
if ( ret != STATUS_OK )
|
||||||
goto out2;
|
goto out2;
|
||||||
@ -1730,7 +1803,9 @@ descend:
|
|||||||
ih = &icx->ir->index;
|
ih = &icx->ir->index;
|
||||||
entry = ntfs_ie_get_by_pos( ih, entry_pos );
|
entry = ntfs_ie_get_by_pos( ih, entry_pos );
|
||||||
|
|
||||||
} else if (new_size > le32_to_cpu(ih->allocated_size)) {
|
}
|
||||||
|
else if ( new_size > le32_to_cpu( ih->allocated_size ) )
|
||||||
|
{
|
||||||
icx->pindex = pindex;
|
icx->pindex = pindex;
|
||||||
ret = ntfs_ib_split( icx, icx->ib );
|
ret = ntfs_ib_split( icx, icx->ib );
|
||||||
if ( ret == STATUS_OK )
|
if ( ret == STATUS_OK )
|
||||||
@ -1742,20 +1817,22 @@ descend:
|
|||||||
ntfs_ie_delete( ih, entry );
|
ntfs_ie_delete( ih, entry );
|
||||||
ntfs_ie_insert( ih, ie, entry );
|
ntfs_ie_insert( ih, ie, entry );
|
||||||
|
|
||||||
if (icx->is_in_root) {
|
if ( icx->is_in_root )
|
||||||
|
{
|
||||||
if ( ntfs_ir_truncate( icx, new_size ) )
|
if ( ntfs_ir_truncate( icx, new_size ) )
|
||||||
goto out2;
|
goto out2;
|
||||||
} else
|
}
|
||||||
if (ntfs_icx_ib_write(icx))
|
else if ( ntfs_icx_ib_write( icx ) )
|
||||||
goto out2;
|
goto out2;
|
||||||
|
|
||||||
ntfs_ie_delete( &ib->index, ie_succ );
|
ntfs_ie_delete( &ib->index, ie_succ );
|
||||||
|
|
||||||
if (ntfs_ih_zero_entry(&ib->index)) {
|
if ( ntfs_ih_zero_entry( &ib->index ) )
|
||||||
|
{
|
||||||
if ( ntfs_index_rm_leaf( icx ) )
|
if ( ntfs_index_rm_leaf( icx ) )
|
||||||
goto out2;
|
goto out2;
|
||||||
} else
|
}
|
||||||
if (ntfs_ib_write(icx, ib))
|
else if ( ntfs_ib_write( icx, ib ) )
|
||||||
goto out2;
|
goto out2;
|
||||||
|
|
||||||
ret = STATUS_OK;
|
ret = STATUS_OK;
|
||||||
@ -1784,7 +1861,8 @@ int ntfs_index_rm(ntfs_index_context *icx)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) {
|
if ( !icx || ( !icx->ib && !icx->ir ) || ntfs_ie_end( icx->entry ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Invalid arguments.\n" );
|
ntfs_log_error( "Invalid arguments.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -1794,22 +1872,28 @@ int ntfs_index_rm(ntfs_index_context *icx)
|
|||||||
else
|
else
|
||||||
ih = &icx->ib->index;
|
ih = &icx->ib->index;
|
||||||
|
|
||||||
if (icx->entry->ie_flags & INDEX_ENTRY_NODE) {
|
if ( icx->entry->ie_flags & INDEX_ENTRY_NODE )
|
||||||
|
{
|
||||||
|
|
||||||
ret = ntfs_index_rm_node( icx );
|
ret = ntfs_index_rm_node( icx );
|
||||||
|
|
||||||
} else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) {
|
}
|
||||||
|
else if ( icx->is_in_root || !ntfs_ih_one_entry( ih ) )
|
||||||
|
{
|
||||||
|
|
||||||
ntfs_ie_delete( ih, icx->entry );
|
ntfs_ie_delete( ih, icx->entry );
|
||||||
|
|
||||||
if (icx->is_in_root) {
|
if ( icx->is_in_root )
|
||||||
|
{
|
||||||
err = ntfs_ir_truncate( icx, le32_to_cpu( ih->index_length ) );
|
err = ntfs_ir_truncate( icx, le32_to_cpu( ih->index_length ) );
|
||||||
if ( err != STATUS_OK )
|
if ( err != STATUS_OK )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
} else
|
}
|
||||||
if (ntfs_icx_ib_write(icx))
|
else if ( ntfs_icx_ib_write( icx ) )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( ntfs_index_rm_leaf( icx ) )
|
if ( ntfs_index_rm_leaf( icx ) )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -1830,14 +1914,16 @@ int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
|||||||
if ( !icx )
|
if ( !icx )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (1) {
|
while ( 1 )
|
||||||
|
{
|
||||||
|
|
||||||
if ( ntfs_index_lookup( key, keylen, icx ) )
|
if ( ntfs_index_lookup( key, keylen, icx ) )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
if ( ( ( ( FILE_NAME_ATTR * )icx->data )->file_attributes &
|
if ( ( ( ( FILE_NAME_ATTR * )icx->data )->file_attributes &
|
||||||
FILE_ATTR_REPARSE_POINT )
|
FILE_ATTR_REPARSE_POINT )
|
||||||
&& !ntfs_possible_symlink(ni)) {
|
&& !ntfs_possible_symlink( ni ) )
|
||||||
|
{
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -1910,9 +1996,11 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
|
|||||||
s64 vcn;
|
s64 vcn;
|
||||||
|
|
||||||
entry = ie;
|
entry = ie;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
vcn = ntfs_ie_get_vcn( entry );
|
vcn = ntfs_ie_get_vcn( entry );
|
||||||
if (ictx->is_in_root) {
|
if ( ictx->is_in_root )
|
||||||
|
{
|
||||||
|
|
||||||
/* down from level zero */
|
/* down from level zero */
|
||||||
|
|
||||||
@ -1920,7 +2008,9 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
|
|||||||
ictx->ib = ( INDEX_BLOCK* )ntfs_malloc( ictx->block_size );
|
ictx->ib = ( INDEX_BLOCK* )ntfs_malloc( ictx->block_size );
|
||||||
ictx->pindex = 1;
|
ictx->pindex = 1;
|
||||||
ictx->is_in_root = FALSE;
|
ictx->is_in_root = FALSE;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
/* down from non-zero level */
|
/* down from non-zero level */
|
||||||
|
|
||||||
@ -1928,12 +2018,15 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
|
|||||||
}
|
}
|
||||||
ictx->parent_pos[ictx->pindex] = 0;
|
ictx->parent_pos[ictx->pindex] = 0;
|
||||||
ictx->parent_vcn[ictx->pindex] = vcn;
|
ictx->parent_vcn[ictx->pindex] = vcn;
|
||||||
if (!ntfs_ib_read(ictx,vcn,ictx->ib)) {
|
if ( !ntfs_ib_read( ictx, vcn, ictx->ib ) )
|
||||||
|
{
|
||||||
ictx->entry = ntfs_ie_get_first( &ictx->ib->index );
|
ictx->entry = ntfs_ie_get_first( &ictx->ib->index );
|
||||||
entry = ictx->entry;
|
entry = ictx->entry;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
entry = ( INDEX_ENTRY* )NULL;
|
entry = ( INDEX_ENTRY* )NULL;
|
||||||
} while (entry && (entry->ie_flags & INDEX_ENTRY_NODE));
|
}
|
||||||
|
while ( entry && ( entry->ie_flags & INDEX_ENTRY_NODE ) );
|
||||||
return ( entry );
|
return ( entry );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1950,10 +2043,13 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
|
|||||||
s64 vcn;
|
s64 vcn;
|
||||||
|
|
||||||
entry = ie;
|
entry = ie;
|
||||||
if (ictx->pindex > 0) {
|
if ( ictx->pindex > 0 )
|
||||||
do {
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
ictx->pindex--;
|
ictx->pindex--;
|
||||||
if (!ictx->pindex) {
|
if ( !ictx->pindex )
|
||||||
|
{
|
||||||
|
|
||||||
/* we have reached the root */
|
/* we have reached the root */
|
||||||
|
|
||||||
@ -1972,20 +2068,26 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
|
|||||||
ictx->parent_pos[ictx->pindex] );
|
ictx->parent_pos[ictx->pindex] );
|
||||||
else
|
else
|
||||||
entry = ( INDEX_ENTRY* )NULL;
|
entry = ( INDEX_ENTRY* )NULL;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* up into non-root node */
|
/* up into non-root node */
|
||||||
vcn = ictx->parent_vcn[ictx->pindex];
|
vcn = ictx->parent_vcn[ictx->pindex];
|
||||||
if (!ntfs_ib_read(ictx,vcn,ictx->ib)) {
|
if ( !ntfs_ib_read( ictx, vcn, ictx->ib ) )
|
||||||
|
{
|
||||||
entry = ntfs_ie_get_by_pos(
|
entry = ntfs_ie_get_by_pos(
|
||||||
&ictx->ib->index,
|
&ictx->ib->index,
|
||||||
ictx->parent_pos[ictx->pindex] );
|
ictx->parent_pos[ictx->pindex] );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
entry = ( INDEX_ENTRY* )NULL;
|
entry = ( INDEX_ENTRY* )NULL;
|
||||||
}
|
}
|
||||||
ictx->entry = entry;
|
ictx->entry = entry;
|
||||||
} while (entry && (ictx->pindex > 0)
|
}
|
||||||
|
while ( entry && ( ictx->pindex > 0 )
|
||||||
&& ( entry->ie_flags & INDEX_ENTRY_END ) );
|
&& ( entry->ie_flags & INDEX_ENTRY_END ) );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
entry = ( INDEX_ENTRY* )NULL;
|
entry = ( INDEX_ENTRY* )NULL;
|
||||||
return ( entry );
|
return ( entry );
|
||||||
}
|
}
|
||||||
@ -2030,7 +2132,8 @@ INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx)
|
|||||||
|
|
||||||
if ( ie->ie_flags & INDEX_ENTRY_END )
|
if ( ie->ie_flags & INDEX_ENTRY_END )
|
||||||
next = ntfs_index_walk_up( ie, ictx );
|
next = ntfs_index_walk_up( ie, ictx );
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* get next entry in same node
|
* get next entry in same node
|
||||||
* there is always one after any entry with data
|
* there is always one after any entry with data
|
||||||
@ -2042,13 +2145,17 @@ INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx)
|
|||||||
|
|
||||||
/* walk down if it has a subnode */
|
/* walk down if it has a subnode */
|
||||||
|
|
||||||
if (flags & INDEX_ENTRY_NODE) {
|
if ( flags & INDEX_ENTRY_NODE )
|
||||||
|
{
|
||||||
next = ntfs_index_walk_down( next, ictx );
|
next = ntfs_index_walk_down( next, ictx );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
/* walk up it has no subnode, nor data */
|
/* walk up it has no subnode, nor data */
|
||||||
|
|
||||||
if (flags & INDEX_ENTRY_END) {
|
if ( flags & INDEX_ENTRY_END )
|
||||||
|
{
|
||||||
next = ntfs_index_walk_up( next, ictx );
|
next = ntfs_index_walk_up( next, ictx );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,8 @@ typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
|||||||
* the call to ntfs_index_ctx_put() to ensure that the changes are written
|
* the call to ntfs_index_ctx_put() to ensure that the changes are written
|
||||||
* to disk.
|
* to disk.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
ntfschar *name;
|
ntfschar *name;
|
||||||
u32 name_len;
|
u32 name_len;
|
||||||
|
@ -166,7 +166,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
int olderrno;
|
int olderrno;
|
||||||
|
|
||||||
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
|
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
|
||||||
if (!vol) {
|
if ( !vol )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -175,7 +176,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
goto out;
|
goto out;
|
||||||
if ( ntfs_file_record_read( vol, mref, &ni->mrec, NULL ) )
|
if ( ntfs_file_record_read( vol, mref, &ni->mrec, NULL ) )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) {
|
if ( !( ni->mrec->flags & MFT_RECORD_IN_USE ) )
|
||||||
|
{
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -185,7 +187,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
/* Receive some basic information about inode. */
|
/* Receive some basic information about inode. */
|
||||||
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
|
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
|
||||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
if ( !ni->mrec->base_mft_record )
|
if ( !ni->mrec->base_mft_record )
|
||||||
ntfs_log_perror( "No STANDARD_INFORMATION in base record"
|
ntfs_log_perror( "No STANDARD_INFORMATION in base record"
|
||||||
" %lld", ( long long )MREF( mref ) );
|
" %lld", ( long long )MREF( mref ) );
|
||||||
@ -201,13 +204,16 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
/* JPA insert v3 extensions if present */
|
/* JPA insert v3 extensions if present */
|
||||||
/* length may be seen as 72 (v1.x) or 96 (v3.x) */
|
/* length may be seen as 72 (v1.x) or 96 (v3.x) */
|
||||||
lthle = ctx->attr->length;
|
lthle = ctx->attr->length;
|
||||||
if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) {
|
if ( le32_to_cpu( lthle ) > sizeof( STANDARD_INFORMATION ) )
|
||||||
|
{
|
||||||
set_nino_flag( ni, v3_Extensions );
|
set_nino_flag( ni, v3_Extensions );
|
||||||
ni->owner_id = std_info->owner_id;
|
ni->owner_id = std_info->owner_id;
|
||||||
ni->security_id = std_info->security_id;
|
ni->security_id = std_info->security_id;
|
||||||
ni->quota_charged = std_info->quota_charged;
|
ni->quota_charged = std_info->quota_charged;
|
||||||
ni->usn = std_info->usn;
|
ni->usn = std_info->usn;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
clear_nino_flag( ni, v3_Extensions );
|
clear_nino_flag( ni, v3_Extensions );
|
||||||
ni->owner_id = const_cpu_to_le32( 0 );
|
ni->owner_id = const_cpu_to_le32( 0 );
|
||||||
ni->security_id = const_cpu_to_le32( 0 );
|
ni->security_id = const_cpu_to_le32( 0 );
|
||||||
@ -215,7 +221,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
/* Set attribute list information. */
|
/* Set attribute list information. */
|
||||||
olderrno = errno;
|
olderrno = errno;
|
||||||
if ( ntfs_attr_lookup( AT_ATTRIBUTE_LIST, AT_UNNAMED, 0,
|
if ( ntfs_attr_lookup( AT_ATTRIBUTE_LIST, AT_UNNAMED, 0,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
if ( errno != ENOENT )
|
if ( errno != ENOENT )
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
/* Attribute list attribute does not present. */
|
/* Attribute list attribute does not present. */
|
||||||
@ -227,7 +234,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
l = ntfs_get_attribute_value_length( ctx->attr );
|
l = ntfs_get_attribute_value_length( ctx->attr );
|
||||||
if ( !l )
|
if ( !l )
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
if (l > 0x40000) {
|
if ( l > 0x40000 )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Too large attrlist attribute (%lld), inode "
|
ntfs_log_perror( "Too large attrlist attribute (%lld), inode "
|
||||||
"%lld", ( long long )l, ( long long )MREF( mref ) );
|
"%lld", ( long long )l, ( long long )MREF( mref ) );
|
||||||
@ -240,7 +248,8 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
l = ntfs_get_attribute_value( vol, ctx->attr, ni->attr_list );
|
l = ntfs_get_attribute_value( vol, ctx->attr, ni->attr_list );
|
||||||
if ( !l )
|
if ( !l )
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
if (l != ni->attr_list_size) {
|
if ( l != ni->attr_list_size )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Unexpected attrlist size (%lld <> %u), inode "
|
ntfs_log_perror( "Unexpected attrlist size (%lld <> %u), inode "
|
||||||
"%lld", ( long long )l, ni->attr_list_size,
|
"%lld", ( long long )l, ni->attr_list_size,
|
||||||
@ -249,15 +258,19 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
}
|
}
|
||||||
get_size:
|
get_size:
|
||||||
olderrno = errno;
|
olderrno = errno;
|
||||||
if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
|
if ( ntfs_attr_lookup( AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
if ( errno != ENOENT )
|
if ( errno != ENOENT )
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
/* Directory or special file. */
|
/* Directory or special file. */
|
||||||
/* restore previous errno to avoid misinterpretation */
|
/* restore previous errno to avoid misinterpretation */
|
||||||
errno = olderrno;
|
errno = olderrno;
|
||||||
ni->data_size = ni->allocated_size = 0;
|
ni->data_size = ni->allocated_size = 0;
|
||||||
} else {
|
}
|
||||||
if (ctx->attr->non_resident) {
|
else
|
||||||
|
{
|
||||||
|
if ( ctx->attr->non_resident )
|
||||||
|
{
|
||||||
ni->data_size = sle64_to_cpu( ctx->attr->data_size );
|
ni->data_size = sle64_to_cpu( ctx->attr->data_size );
|
||||||
if ( ctx->attr->flags &
|
if ( ctx->attr->flags &
|
||||||
( ATTR_IS_COMPRESSED | ATTR_IS_SPARSE ) )
|
( ATTR_IS_COMPRESSED | ATTR_IS_SPARSE ) )
|
||||||
@ -266,7 +279,9 @@ get_size:
|
|||||||
else
|
else
|
||||||
ni->allocated_size = sle64_to_cpu(
|
ni->allocated_size = sle64_to_cpu(
|
||||||
ctx->attr->allocated_size );
|
ctx->attr->allocated_size );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ni->data_size = le32_to_cpu( ctx->attr->value_length );
|
ni->data_size = le32_to_cpu( ctx->attr->value_length );
|
||||||
ni->allocated_size = ( ni->data_size + 7 ) & ~7;
|
ni->allocated_size = ( ni->data_size + 7 ) & ~7;
|
||||||
}
|
}
|
||||||
@ -320,23 +335,30 @@ int ntfs_inode_real_close(ntfs_inode *ni)
|
|||||||
ntfs_log_enter( "Entering for inode %lld\n", ( long long )ni->mft_no );
|
ntfs_log_enter( "Entering for inode %lld\n", ( long long )ni->mft_no );
|
||||||
|
|
||||||
/* If we have dirty metadata, write it out. */
|
/* If we have dirty metadata, write it out. */
|
||||||
if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
|
if ( NInoDirty( ni ) || NInoAttrListDirty( ni ) )
|
||||||
if (ntfs_inode_sync(ni)) {
|
{
|
||||||
|
if ( ntfs_inode_sync( ni ) )
|
||||||
|
{
|
||||||
if ( errno != EIO )
|
if ( errno != EIO )
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Is this a base inode with mapped extent inodes? */
|
/* Is this a base inode with mapped extent inodes? */
|
||||||
if (ni->nr_extents > 0) {
|
if ( ni->nr_extents > 0 )
|
||||||
while (ni->nr_extents > 0) {
|
{
|
||||||
if (ntfs_inode_real_close(ni->extent_nis[0])) {
|
while ( ni->nr_extents > 0 )
|
||||||
|
{
|
||||||
|
if ( ntfs_inode_real_close( ni->extent_nis[0] ) )
|
||||||
|
{
|
||||||
if ( errno != EIO )
|
if ( errno != EIO )
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ni->nr_extents == -1) {
|
}
|
||||||
|
else if ( ni->nr_extents == -1 )
|
||||||
|
{
|
||||||
ntfs_inode **tmp_nis;
|
ntfs_inode **tmp_nis;
|
||||||
ntfs_inode *base_ni;
|
ntfs_inode *base_ni;
|
||||||
s32 i;
|
s32 i;
|
||||||
@ -346,7 +368,8 @@ int ntfs_inode_real_close(ntfs_inode *ni)
|
|||||||
* base inode before destroying it.
|
* base inode before destroying it.
|
||||||
*/
|
*/
|
||||||
base_ni = ni->base_ni;
|
base_ni = ni->base_ni;
|
||||||
for (i = 0; i < base_ni->nr_extents; ++i) {
|
for ( i = 0; i < base_ni->nr_extents; ++i )
|
||||||
|
{
|
||||||
tmp_nis = base_ni->extent_nis;
|
tmp_nis = base_ni->extent_nis;
|
||||||
if ( tmp_nis[i] != ni )
|
if ( tmp_nis[i] != ni )
|
||||||
continue;
|
continue;
|
||||||
@ -355,7 +378,8 @@ int ntfs_inode_real_close(ntfs_inode *ni)
|
|||||||
( base_ni->nr_extents - i - 1 ) *
|
( base_ni->nr_extents - i - 1 ) *
|
||||||
sizeof( ntfs_inode * ) );
|
sizeof( ntfs_inode * ) );
|
||||||
/* Buffer should be for multiple of four extents. */
|
/* Buffer should be for multiple of four extents. */
|
||||||
if ((--base_ni->nr_extents) & 3) {
|
if ( ( --base_ni->nr_extents ) & 3 )
|
||||||
|
{
|
||||||
i = -1;
|
i = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -363,14 +387,17 @@ int ntfs_inode_real_close(ntfs_inode *ni)
|
|||||||
* ElectricFence is unhappy with realloc(x,0) as free(x)
|
* ElectricFence is unhappy with realloc(x,0) as free(x)
|
||||||
* thus we explicitly separate these two cases.
|
* thus we explicitly separate these two cases.
|
||||||
*/
|
*/
|
||||||
if (base_ni->nr_extents) {
|
if ( base_ni->nr_extents )
|
||||||
|
{
|
||||||
/* Resize the memory buffer. */
|
/* Resize the memory buffer. */
|
||||||
tmp_nis = realloc( tmp_nis, base_ni->nr_extents *
|
tmp_nis = realloc( tmp_nis, base_ni->nr_extents *
|
||||||
sizeof( ntfs_inode * ) );
|
sizeof( ntfs_inode * ) );
|
||||||
/* Ignore errors, they don't really matter. */
|
/* Ignore errors, they don't really matter. */
|
||||||
if ( tmp_nis )
|
if ( tmp_nis )
|
||||||
base_ni->extent_nis = tmp_nis;
|
base_ni->extent_nis = tmp_nis;
|
||||||
} else if (tmp_nis) {
|
}
|
||||||
|
else if ( tmp_nis )
|
||||||
|
{
|
||||||
free( tmp_nis );
|
free( tmp_nis );
|
||||||
base_ni->extent_nis = ( ntfs_inode** )NULL;
|
base_ni->extent_nis = ( ntfs_inode** )NULL;
|
||||||
}
|
}
|
||||||
@ -473,12 +500,15 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
|
|||||||
item.varsize = 0;
|
item.varsize = 0;
|
||||||
cached = ( struct CACHED_NIDATA* )ntfs_fetch_cache( vol->nidata_cache,
|
cached = ( struct CACHED_NIDATA* )ntfs_fetch_cache( vol->nidata_cache,
|
||||||
GENERIC( &item ), idata_cache_compare );
|
GENERIC( &item ), idata_cache_compare );
|
||||||
if (cached) {
|
if ( cached )
|
||||||
|
{
|
||||||
ni = cached->ni;
|
ni = cached->ni;
|
||||||
/* do not keep open entries in cache */
|
/* do not keep open entries in cache */
|
||||||
ntfs_remove_cache( vol->nidata_cache,
|
ntfs_remove_cache( vol->nidata_cache,
|
||||||
( struct CACHED_GENERIC* )cached, 0 );
|
( struct CACHED_GENERIC* )cached, 0 );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ni = ntfs_inode_real_open( vol, mref );
|
ni = ntfs_inode_real_open( vol, mref );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -504,24 +534,29 @@ int ntfs_inode_close(ntfs_inode *ni)
|
|||||||
BOOL dirty;
|
BOOL dirty;
|
||||||
struct CACHED_NIDATA item;
|
struct CACHED_NIDATA item;
|
||||||
|
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
debug_double_inode( ni->mft_no, 0 );
|
debug_double_inode( ni->mft_no, 0 );
|
||||||
/* do not cache system files : could lead to double entries */
|
/* do not cache system files : could lead to double entries */
|
||||||
if ( ni->vol && ni->vol->nidata_cache
|
if ( ni->vol && ni->vol->nidata_cache
|
||||||
&& ( ( ni->mft_no == FILE_root )
|
&& ( ( ni->mft_no == FILE_root )
|
||||||
|| ( ( ni->mft_no >= FILE_first_user )
|
|| ( ( ni->mft_no >= FILE_first_user )
|
||||||
&& !(ni->mrec->flags & MFT_RECORD_IS_4)))) {
|
&& !( ni->mrec->flags & MFT_RECORD_IS_4 ) ) ) )
|
||||||
|
{
|
||||||
/* If we have dirty metadata, write it out. */
|
/* If we have dirty metadata, write it out. */
|
||||||
dirty = NInoDirty( ni ) || NInoAttrListDirty( ni );
|
dirty = NInoDirty( ni ) || NInoAttrListDirty( ni );
|
||||||
if (dirty) {
|
if ( dirty )
|
||||||
|
{
|
||||||
res = ntfs_inode_sync( ni );
|
res = ntfs_inode_sync( ni );
|
||||||
/* do a real close if sync failed */
|
/* do a real close if sync failed */
|
||||||
if ( res )
|
if ( res )
|
||||||
ntfs_inode_real_close( ni );
|
ntfs_inode_real_close( ni );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res = 0;
|
res = 0;
|
||||||
|
|
||||||
if (!res) {
|
if ( !res )
|
||||||
|
{
|
||||||
/* feed idata into cache */
|
/* feed idata into cache */
|
||||||
item.inum = ni->mft_no;
|
item.inum = ni->mft_no;
|
||||||
item.ni = ni;
|
item.ni = ni;
|
||||||
@ -531,11 +566,14 @@ int ntfs_inode_close(ntfs_inode *ni)
|
|||||||
ntfs_enter_cache( ni->vol->nidata_cache,
|
ntfs_enter_cache( ni->vol->nidata_cache,
|
||||||
GENERIC( &item ), idata_cache_compare );
|
GENERIC( &item ), idata_cache_compare );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* cache not ready or system file, really close */
|
/* cache not ready or system file, really close */
|
||||||
res = ntfs_inode_real_close( ni );
|
res = ntfs_inode_real_close( ni );
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res = 0;
|
res = 0;
|
||||||
#else
|
#else
|
||||||
res = ntfs_inode_real_close( ni );
|
res = ntfs_inode_real_close( ni );
|
||||||
@ -575,7 +613,8 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
|||||||
ntfs_inode **extent_nis;
|
ntfs_inode **extent_nis;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!base_ni) {
|
if ( !base_ni )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
ntfs_log_perror( "%s", __FUNCTION__ );
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -586,9 +625,11 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
|||||||
( unsigned long long )base_ni->mft_no );
|
( unsigned long long )base_ni->mft_no );
|
||||||
|
|
||||||
/* Is the extent inode already open and attached to the base inode? */
|
/* Is the extent inode already open and attached to the base inode? */
|
||||||
if (base_ni->nr_extents > 0) {
|
if ( base_ni->nr_extents > 0 )
|
||||||
|
{
|
||||||
extent_nis = base_ni->extent_nis;
|
extent_nis = base_ni->extent_nis;
|
||||||
for (i = 0; i < base_ni->nr_extents; i++) {
|
for ( i = 0; i < base_ni->nr_extents; i++ )
|
||||||
|
{
|
||||||
u16 seq_no;
|
u16 seq_no;
|
||||||
|
|
||||||
ni = extent_nis[i];
|
ni = extent_nis[i];
|
||||||
@ -597,7 +638,8 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
|||||||
/* Verify the sequence number if given. */
|
/* Verify the sequence number if given. */
|
||||||
seq_no = MSEQNO_LE( mref );
|
seq_no = MSEQNO_LE( mref );
|
||||||
if ( seq_no && seq_no != le16_to_cpu(
|
if ( seq_no && seq_no != le16_to_cpu(
|
||||||
ni->mrec->sequence_number)) {
|
ni->mrec->sequence_number ) )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Found stale extent mft "
|
ntfs_log_perror( "Found stale extent mft "
|
||||||
"reference mft=%lld",
|
"reference mft=%lld",
|
||||||
@ -617,13 +659,15 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
|||||||
ni->nr_extents = -1;
|
ni->nr_extents = -1;
|
||||||
ni->base_ni = base_ni;
|
ni->base_ni = base_ni;
|
||||||
/* Attach extent inode to base inode, reallocating memory if needed. */
|
/* Attach extent inode to base inode, reallocating memory if needed. */
|
||||||
if (!(base_ni->nr_extents & 3)) {
|
if ( !( base_ni->nr_extents & 3 ) )
|
||||||
|
{
|
||||||
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
||||||
|
|
||||||
extent_nis = ntfs_malloc( i );
|
extent_nis = ntfs_malloc( i );
|
||||||
if ( !extent_nis )
|
if ( !extent_nis )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
if (base_ni->nr_extents) {
|
if ( base_ni->nr_extents )
|
||||||
|
{
|
||||||
memcpy( extent_nis, base_ni->extent_nis,
|
memcpy( extent_nis, base_ni->extent_nis,
|
||||||
i - 4 * sizeof( ntfs_inode * ) );
|
i - 4 * sizeof( ntfs_inode * ) );
|
||||||
free( base_ni->extent_nis );
|
free( base_ni->extent_nis );
|
||||||
@ -651,7 +695,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
|||||||
ATTR_LIST_ENTRY *ale;
|
ATTR_LIST_ENTRY *ale;
|
||||||
u64 prev_attached = 0;
|
u64 prev_attached = 0;
|
||||||
|
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Invalid arguments.\n" );
|
ntfs_log_trace( "Invalid arguments.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -666,7 +711,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
|||||||
if ( !NInoAttrList( ni ) )
|
if ( !NInoAttrList( ni ) )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!ni->attr_list) {
|
if ( !ni->attr_list )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -675,10 +721,13 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
|
|||||||
/* Walk through attribute list and attach all extents. */
|
/* Walk through attribute list and attach all extents. */
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
|
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
|
||||||
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
|
||||||
|
{
|
||||||
if ( ni->mft_no != MREF_LE( ale->mft_reference ) &&
|
if ( ni->mft_no != MREF_LE( ale->mft_reference ) &&
|
||||||
prev_attached != MREF_LE(ale->mft_reference)) {
|
prev_attached != MREF_LE( ale->mft_reference ) )
|
||||||
if (!ntfs_extent_inode_open(ni, ale->mft_reference)) {
|
{
|
||||||
|
if ( !ntfs_extent_inode_open( ni, ale->mft_reference ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Couldn't attach extent inode.\n" );
|
ntfs_log_trace( "Couldn't attach extent inode.\n" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -708,7 +757,8 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
|
|||||||
if ( !ctx )
|
if ( !ctx )
|
||||||
return -1;
|
return -1;
|
||||||
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
|
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
|
||||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to sync standard info (inode %lld)",
|
ntfs_log_perror( "Failed to sync standard info (inode %lld)",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
@ -717,7 +767,8 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
|
|||||||
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
||||||
le16_to_cpu( ctx->attr->value_offset ) );
|
le16_to_cpu( ctx->attr->value_offset ) );
|
||||||
std_info->file_attributes = ni->flags;
|
std_info->file_attributes = ni->flags;
|
||||||
if (!test_nino_flag(ni, TimesSet)) {
|
if ( !test_nino_flag( ni, TimesSet ) )
|
||||||
|
{
|
||||||
std_info->creation_time = ni->creation_time;
|
std_info->creation_time = ni->creation_time;
|
||||||
std_info->last_data_change_time = ni->last_data_change_time;
|
std_info->last_data_change_time = ni->last_data_change_time;
|
||||||
std_info->last_mft_change_time = ni->last_mft_change_time;
|
std_info->last_mft_change_time = ni->last_mft_change_time;
|
||||||
@ -732,7 +783,8 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
|
|||||||
&& ( lth <= sizeof( STANDARD_INFORMATION ) ) )
|
&& ( lth <= sizeof( STANDARD_INFORMATION ) ) )
|
||||||
ntfs_log_error( "bad sync of standard information\n" );
|
ntfs_log_error( "bad sync of standard information\n" );
|
||||||
|
|
||||||
if (lth > sizeof(STANDARD_INFORMATION)) {
|
if ( lth > sizeof( STANDARD_INFORMATION ) )
|
||||||
|
{
|
||||||
std_info->owner_id = ni->owner_id;
|
std_info->owner_id = ni->owner_id;
|
||||||
std_info->security_id = ni->security_id;
|
std_info->security_id = ni->security_id;
|
||||||
std_info->quota_charged = ni->quota_charged;
|
std_info->quota_charged = ni->quota_charged;
|
||||||
@ -765,15 +817,18 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
ntfs_log_trace( "Entering for inode %lld\n", ( long long )ni->mft_no );
|
ntfs_log_trace( "Entering for inode %lld\n", ( long long )ni->mft_no );
|
||||||
|
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||||
if (!ctx) {
|
if ( !ctx )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* Collect the reparse tag, if any */
|
/* Collect the reparse tag, if any */
|
||||||
reparse_tag = cpu_to_le32( 0 );
|
reparse_tag = cpu_to_le32( 0 );
|
||||||
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
|
if ( ni->flags & FILE_ATTR_REPARSE_POINT )
|
||||||
|
{
|
||||||
if ( !ntfs_attr_lookup( AT_REPARSE_POINT, NULL,
|
if ( !ntfs_attr_lookup( AT_REPARSE_POINT, NULL,
|
||||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
rpp = ( REPARSE_POINT* )( ( u8 * )ctx->attr +
|
rpp = ( REPARSE_POINT* )( ( u8 * )ctx->attr +
|
||||||
le16_to_cpu( ctx->attr->value_offset ) );
|
le16_to_cpu( ctx->attr->value_offset ) );
|
||||||
reparse_tag = rpp->reparse_tag;
|
reparse_tag = rpp->reparse_tag;
|
||||||
@ -781,10 +836,12 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
}
|
}
|
||||||
/* Walk through all FILE_NAME attributes and update them. */
|
/* Walk through all FILE_NAME attributes and update them. */
|
||||||
while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) {
|
while ( !ntfs_attr_lookup( AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
fn = ( FILE_NAME_ATTR * )( ( u8 * )ctx->attr +
|
fn = ( FILE_NAME_ATTR * )( ( u8 * )ctx->attr +
|
||||||
le16_to_cpu( ctx->attr->value_offset ) );
|
le16_to_cpu( ctx->attr->value_offset ) );
|
||||||
if (MREF_LE(fn->parent_directory) == ni->mft_no) {
|
if ( MREF_LE( fn->parent_directory ) == ni->mft_no )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* WARNING: We cheat here and obtain 2 attribute
|
* WARNING: We cheat here and obtain 2 attribute
|
||||||
* search contexts for one inode (first we obtained
|
* search contexts for one inode (first we obtained
|
||||||
@ -793,13 +850,14 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
* but will deadlock in the kernel.
|
* but will deadlock in the kernel.
|
||||||
*/
|
*/
|
||||||
index_ni = ni;
|
index_ni = ni;
|
||||||
} else
|
}
|
||||||
if (dir_ni)
|
else if ( dir_ni )
|
||||||
index_ni = dir_ni;
|
index_ni = dir_ni;
|
||||||
else
|
else
|
||||||
index_ni = ntfs_inode_open( ni->vol,
|
index_ni = ntfs_inode_open( ni->vol,
|
||||||
le64_to_cpu( fn->parent_directory ) );
|
le64_to_cpu( fn->parent_directory ) );
|
||||||
if (!index_ni) {
|
if ( !index_ni )
|
||||||
|
{
|
||||||
if ( !err )
|
if ( !err )
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Failed to open inode %lld with index",
|
ntfs_log_perror( "Failed to open inode %lld with index",
|
||||||
@ -807,7 +865,8 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ictx = ntfs_index_ctx_get( index_ni, NTFS_INDEX_I30, 4 );
|
ictx = ntfs_index_ctx_get( index_ni, NTFS_INDEX_I30, 4 );
|
||||||
if (!ictx) {
|
if ( !ictx )
|
||||||
|
{
|
||||||
if ( !err )
|
if ( !err )
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Failed to get index ctx, inode %lld",
|
ntfs_log_perror( "Failed to get index ctx, inode %lld",
|
||||||
@ -817,8 +876,10 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
err = errno;
|
err = errno;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) {
|
if ( ntfs_index_lookup( fn, sizeof( FILE_NAME_ATTR ), ictx ) )
|
||||||
if (!err) {
|
{
|
||||||
|
if ( !err )
|
||||||
|
{
|
||||||
if ( errno == ENOENT )
|
if ( errno == ENOENT )
|
||||||
err = EIO;
|
err = EIO;
|
||||||
else
|
else
|
||||||
@ -839,18 +900,22 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
if ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
|
if ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
|
||||||
fnx->data_size = fnx->allocated_size
|
fnx->data_size = fnx->allocated_size
|
||||||
= const_cpu_to_le64( 0 );
|
= const_cpu_to_le64( 0 );
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
fnx->allocated_size = cpu_to_sle64( ni->allocated_size );
|
fnx->allocated_size = cpu_to_sle64( ni->allocated_size );
|
||||||
fnx->data_size = cpu_to_sle64( ni->data_size );
|
fnx->data_size = cpu_to_sle64( ni->data_size );
|
||||||
}
|
}
|
||||||
/* update or clear the reparse tag in the index */
|
/* update or clear the reparse tag in the index */
|
||||||
fnx->reparse_point_tag = reparse_tag;
|
fnx->reparse_point_tag = reparse_tag;
|
||||||
if (!test_nino_flag(ni, TimesSet)) {
|
if ( !test_nino_flag( ni, TimesSet ) )
|
||||||
|
{
|
||||||
fnx->creation_time = ni->creation_time;
|
fnx->creation_time = ni->creation_time;
|
||||||
fnx->last_data_change_time = ni->last_data_change_time;
|
fnx->last_data_change_time = ni->last_data_change_time;
|
||||||
fnx->last_mft_change_time = ni->last_mft_change_time;
|
fnx->last_mft_change_time = ni->last_mft_change_time;
|
||||||
fnx->last_access_time = ni->last_access_time;
|
fnx->last_access_time = ni->last_access_time;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fnx->creation_time = fn->creation_time;
|
fnx->creation_time = fn->creation_time;
|
||||||
fnx->last_data_change_time = fn->last_data_change_time;
|
fnx->last_data_change_time = fn->last_data_change_time;
|
||||||
fnx->last_mft_change_time = fn->last_mft_change_time;
|
fnx->last_mft_change_time = fn->last_mft_change_time;
|
||||||
@ -863,14 +928,16 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
err = errno;
|
err = errno;
|
||||||
}
|
}
|
||||||
/* Check for real error occurred. */
|
/* Check for real error occurred. */
|
||||||
if (errno != ENOENT) {
|
if ( errno != ENOENT )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Attribute lookup failed, inode %lld",
|
ntfs_log_perror( "Attribute lookup failed, inode %lld",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
if (err) {
|
if ( err )
|
||||||
|
{
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -905,7 +972,8 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_error( "Failed to sync NULL inode\n" );
|
ntfs_log_error( "Failed to sync NULL inode\n" );
|
||||||
return -1;
|
return -1;
|
||||||
@ -915,8 +983,10 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
|
|
||||||
/* Update STANDARD_INFORMATION. */
|
/* Update STANDARD_INFORMATION. */
|
||||||
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
||||||
ntfs_inode_sync_standard_information(ni)) {
|
ntfs_inode_sync_standard_information( ni ) )
|
||||||
if (!err || errno == EIO) {
|
{
|
||||||
|
if ( !err || errno == EIO )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
if ( err != EIO )
|
if ( err != EIO )
|
||||||
err = EBUSY;
|
err = EBUSY;
|
||||||
@ -926,8 +996,10 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
/* Update FILE_NAME's in the index. */
|
/* Update FILE_NAME's in the index. */
|
||||||
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
||||||
NInoFileNameTestAndClearDirty( ni ) &&
|
NInoFileNameTestAndClearDirty( ni ) &&
|
||||||
ntfs_inode_sync_file_name(ni, dir_ni)) {
|
ntfs_inode_sync_file_name( ni, dir_ni ) )
|
||||||
if (!err || errno == EIO) {
|
{
|
||||||
|
if ( !err || errno == EIO )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
if ( err != EIO )
|
if ( err != EIO )
|
||||||
err = EBUSY;
|
err = EBUSY;
|
||||||
@ -939,12 +1011,15 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
|
|
||||||
/* Write out attribute list from cache to disk. */
|
/* Write out attribute list from cache to disk. */
|
||||||
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
if ( ( ni->mrec->flags & MFT_RECORD_IN_USE ) && ni->nr_extents != -1 &&
|
||||||
NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) {
|
NInoAttrList( ni ) && NInoAttrListTestAndClearDirty( ni ) )
|
||||||
|
{
|
||||||
ntfs_attr *na;
|
ntfs_attr *na;
|
||||||
|
|
||||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
if (!err || errno == EIO) {
|
{
|
||||||
|
if ( !err || errno == EIO )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
if ( err != EIO )
|
if ( err != EIO )
|
||||||
err = EBUSY;
|
err = EBUSY;
|
||||||
@ -956,10 +1031,13 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
goto sync_inode;
|
goto sync_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (na->data_size == ni->attr_list_size) {
|
if ( na->data_size == ni->attr_list_size )
|
||||||
|
{
|
||||||
if ( ntfs_attr_pwrite( na, 0, ni->attr_list_size,
|
if ( ntfs_attr_pwrite( na, 0, ni->attr_list_size,
|
||||||
ni->attr_list) != ni->attr_list_size) {
|
ni->attr_list ) != ni->attr_list_size )
|
||||||
if (!err || errno == EIO) {
|
{
|
||||||
|
if ( !err || errno == EIO )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
if ( err != EIO )
|
if ( err != EIO )
|
||||||
err = EBUSY;
|
err = EBUSY;
|
||||||
@ -969,7 +1047,9 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
}
|
}
|
||||||
NInoAttrListSetDirty( ni );
|
NInoAttrListSetDirty( ni );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
err = EIO;
|
err = EIO;
|
||||||
ntfs_log_error( "Attribute list sync failed (bad size, "
|
ntfs_log_error( "Attribute list sync failed (bad size, "
|
||||||
"inode %lld)\n", ( long long )ni->mft_no );
|
"inode %lld)\n", ( long long )ni->mft_no );
|
||||||
@ -980,9 +1060,12 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
|
|
||||||
sync_inode:
|
sync_inode:
|
||||||
/* Write this inode out to the $MFT (and $MFTMirr if applicable). */
|
/* Write this inode out to the $MFT (and $MFTMirr if applicable). */
|
||||||
if (NInoTestAndClearDirty(ni)) {
|
if ( NInoTestAndClearDirty( ni ) )
|
||||||
if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) {
|
{
|
||||||
if (!err || errno == EIO) {
|
if ( ntfs_mft_record_write( ni->vol, ni->mft_no, ni->mrec ) )
|
||||||
|
{
|
||||||
|
if ( !err || errno == EIO )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
if ( err != EIO )
|
if ( err != EIO )
|
||||||
err = EBUSY;
|
err = EBUSY;
|
||||||
@ -994,10 +1077,12 @@ sync_inode:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If this is a base inode with extents write all dirty extents, too. */
|
/* If this is a base inode with extents write all dirty extents, too. */
|
||||||
if (ni->nr_extents > 0) {
|
if ( ni->nr_extents > 0 )
|
||||||
|
{
|
||||||
s32 i;
|
s32 i;
|
||||||
|
|
||||||
for (i = 0; i < ni->nr_extents; ++i) {
|
for ( i = 0; i < ni->nr_extents; ++i )
|
||||||
|
{
|
||||||
ntfs_inode *eni;
|
ntfs_inode *eni;
|
||||||
|
|
||||||
eni = ni->extent_nis[i];
|
eni = ni->extent_nis[i];
|
||||||
@ -1005,8 +1090,10 @@ sync_inode:
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( ntfs_mft_record_write( eni->vol, eni->mft_no,
|
if ( ntfs_mft_record_write( eni->vol, eni->mft_no,
|
||||||
eni->mrec)) {
|
eni->mrec ) )
|
||||||
if (!err || errno == EIO) {
|
{
|
||||||
|
if ( !err || errno == EIO )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
if ( err != EIO )
|
if ( err != EIO )
|
||||||
err = EBUSY;
|
err = EBUSY;
|
||||||
@ -1020,7 +1107,8 @@ sync_inode:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if ( err )
|
||||||
|
{
|
||||||
errno = err;
|
errno = err;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
@ -1043,10 +1131,12 @@ int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = ntfs_inode_sync_in_dir( ni, dir_ni );
|
res = ntfs_inode_sync_in_dir( ni, dir_ni );
|
||||||
if (res) {
|
if ( res )
|
||||||
|
{
|
||||||
if ( errno != EIO )
|
if ( errno != EIO )
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res = ntfs_inode_close( ni );
|
res = ntfs_inode_close( ni );
|
||||||
return ( res );
|
return ( res );
|
||||||
}
|
}
|
||||||
@ -1071,7 +1161,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
ATTR_LIST_ENTRY *ale = NULL;
|
ATTR_LIST_ENTRY *ale = NULL;
|
||||||
ntfs_attr *na;
|
ntfs_attr *na;
|
||||||
|
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
ntfs_log_perror( "%s", __FUNCTION__ );
|
||||||
return -1;
|
return -1;
|
||||||
@ -1079,7 +1170,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
|
|
||||||
ntfs_log_trace( "inode %llu\n", ( unsigned long long ) ni->mft_no );
|
ntfs_log_trace( "inode %llu\n", ( unsigned long long ) ni->mft_no );
|
||||||
|
|
||||||
if (NInoAttrList(ni) || ni->nr_extents) {
|
if ( NInoAttrList( ni ) || ni->nr_extents )
|
||||||
|
{
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
ntfs_log_perror( "Inode already has attribute list" );
|
ntfs_log_perror( "Inode already has attribute list" );
|
||||||
return -1;
|
return -1;
|
||||||
@ -1087,16 +1179,19 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
|
|
||||||
/* Form attribute list. */
|
/* Form attribute list. */
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||||
if (!ctx) {
|
if ( !ctx )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* Walk through all attributes. */
|
/* Walk through all attributes. */
|
||||||
while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) {
|
while ( !ntfs_attr_lookup( AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
|
|
||||||
int ale_size;
|
int ale_size;
|
||||||
|
|
||||||
if (ctx->attr->type == AT_ATTRIBUTE_LIST) {
|
if ( ctx->attr->type == AT_ATTRIBUTE_LIST )
|
||||||
|
{
|
||||||
err = EIO;
|
err = EIO;
|
||||||
ntfs_log_perror( "Attribute list already present" );
|
ntfs_log_perror( "Attribute list already present" );
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
@ -1107,7 +1202,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
al_len += ale_size;
|
al_len += ale_size;
|
||||||
|
|
||||||
aln = realloc( al, al_len );
|
aln = realloc( al, al_len );
|
||||||
if (!aln) {
|
if ( !aln )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Failed to realloc %d bytes", al_len );
|
ntfs_log_perror( "Failed to realloc %d bytes", al_len );
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
@ -1136,7 +1232,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
ale = ( ATTR_LIST_ENTRY * )( al + al_len );
|
ale = ( ATTR_LIST_ENTRY * )( al + al_len );
|
||||||
}
|
}
|
||||||
/* Check for real error occurred. */
|
/* Check for real error occurred. */
|
||||||
if (errno != ENOENT) {
|
if ( errno != ENOENT )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "%s: Attribute lookup failed, inode %lld",
|
ntfs_log_perror( "%s: Attribute lookup failed, inode %lld",
|
||||||
__FUNCTION__, ( long long )ni->mft_no );
|
__FUNCTION__, ( long long )ni->mft_no );
|
||||||
@ -1152,9 +1249,11 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
/* Free space if there is not enough it for $ATTRIBUTE_LIST. */
|
/* Free space if there is not enough it for $ATTRIBUTE_LIST. */
|
||||||
if ( le32_to_cpu( ni->mrec->bytes_allocated ) -
|
if ( le32_to_cpu( ni->mrec->bytes_allocated ) -
|
||||||
le32_to_cpu( ni->mrec->bytes_in_use ) <
|
le32_to_cpu( ni->mrec->bytes_in_use ) <
|
||||||
offsetof(ATTR_RECORD, resident_end)) {
|
offsetof( ATTR_RECORD, resident_end ) )
|
||||||
|
{
|
||||||
if ( ntfs_inode_free_space( ni,
|
if ( ntfs_inode_free_space( ni,
|
||||||
offsetof(ATTR_RECORD, resident_end))) {
|
offsetof( ATTR_RECORD, resident_end ) ) )
|
||||||
|
{
|
||||||
/* Failed to free space. */
|
/* Failed to free space. */
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Failed to free space for attrlist" );
|
ntfs_log_perror( "Failed to free space for attrlist" );
|
||||||
@ -1164,7 +1263,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
|
|
||||||
/* Add $ATTRIBUTE_LIST to mft record. */
|
/* Add $ATTRIBUTE_LIST to mft record. */
|
||||||
if ( ntfs_resident_attr_record_add( ni,
|
if ( ntfs_resident_attr_record_add( ni,
|
||||||
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
|
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0 ) < 0 )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Couldn't add $ATTRIBUTE_LIST to MFT" );
|
ntfs_log_perror( "Couldn't add $ATTRIBUTE_LIST to MFT" );
|
||||||
goto rollback;
|
goto rollback;
|
||||||
@ -1172,12 +1272,14 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
|||||||
|
|
||||||
/* Resize it. */
|
/* Resize it. */
|
||||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||||
if (!na) {
|
if ( !na )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Failed to open just added $ATTRIBUTE_LIST" );
|
ntfs_log_perror( "Failed to open just added $ATTRIBUTE_LIST" );
|
||||||
goto remove_attrlist_record;
|
goto remove_attrlist_record;
|
||||||
}
|
}
|
||||||
if (ntfs_attr_truncate(na, al_len)) {
|
if ( ntfs_attr_truncate( na, al_len ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Failed to resize just added $ATTRIBUTE_LIST" );
|
ntfs_log_perror( "Failed to resize just added $ATTRIBUTE_LIST" );
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
@ -1195,10 +1297,12 @@ remove_attrlist_record:
|
|||||||
/* Remove $ATTRIBUTE_LIST record. */
|
/* Remove $ATTRIBUTE_LIST record. */
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
if ( !ntfs_attr_lookup( AT_ATTRIBUTE_LIST, NULL, 0,
|
if ( !ntfs_attr_lookup( AT_ATTRIBUTE_LIST, NULL, 0,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
if ( ntfs_attr_record_rm( ctx ) )
|
if ( ntfs_attr_record_rm( ctx ) )
|
||||||
ntfs_log_perror( "Rollback failed to remove attrlist" );
|
ntfs_log_perror( "Rollback failed to remove attrlist" );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ntfs_log_perror( "Rollback failed to find attrlist" );
|
ntfs_log_perror( "Rollback failed to find attrlist" );
|
||||||
/* Setup back in-memory runlist. */
|
/* Setup back in-memory runlist. */
|
||||||
ni->attr_list = al;
|
ni->attr_list = al;
|
||||||
@ -1211,17 +1315,21 @@ rollback:
|
|||||||
*/
|
*/
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
ale = ( ATTR_LIST_ENTRY* )al;
|
ale = ( ATTR_LIST_ENTRY* )al;
|
||||||
while ((u8*)ale < al + al_len) {
|
while ( ( u8* )ale < al + al_len )
|
||||||
if (MREF_LE(ale->mft_reference) != ni->mft_no) {
|
{
|
||||||
|
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
|
||||||
|
{
|
||||||
if ( !ntfs_attr_lookup( ale->type, ale->name,
|
if ( !ntfs_attr_lookup( ale->type, ale->name,
|
||||||
ale->name_length,
|
ale->name_length,
|
||||||
CASE_SENSITIVE,
|
CASE_SENSITIVE,
|
||||||
sle64_to_cpu( ale->lowest_vcn ),
|
sle64_to_cpu( ale->lowest_vcn ),
|
||||||
NULL, 0, ctx)) {
|
NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
if ( ntfs_attr_record_move_to( ctx, ni ) )
|
if ( ntfs_attr_record_move_to( ctx, ni ) )
|
||||||
ntfs_log_perror( "Rollback failed to "
|
ntfs_log_perror( "Rollback failed to "
|
||||||
"move attribute" );
|
"move attribute" );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ntfs_log_perror( "Rollback failed to find attr" );
|
ntfs_log_perror( "Rollback failed to find attr" );
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
}
|
}
|
||||||
@ -1252,7 +1360,8 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size)
|
|||||||
ntfs_attr_search_ctx *ctx;
|
ntfs_attr_search_ctx *ctx;
|
||||||
int freed;
|
int freed;
|
||||||
|
|
||||||
if (!ni || size < 0) {
|
if ( !ni || size < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: ni=%p size=%d", __FUNCTION__, ni, size );
|
ntfs_log_perror( "%s: ni=%p size=%d", __FUNCTION__, ni, size );
|
||||||
return -1;
|
return -1;
|
||||||
@ -1277,13 +1386,15 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size)
|
|||||||
if ( ntfs_attr_position( AT_FILE_NAME, ctx ) )
|
if ( ntfs_attr_position( AT_FILE_NAME, ctx ) )
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
|
|
||||||
while (1) {
|
while ( 1 )
|
||||||
|
{
|
||||||
int record_size;
|
int record_size;
|
||||||
/*
|
/*
|
||||||
* Check whether attribute is from different MFT record. If so,
|
* Check whether attribute is from different MFT record. If so,
|
||||||
* find next, because we don't need such.
|
* find next, because we don't need such.
|
||||||
*/
|
*/
|
||||||
while (ctx->ntfs_ino->mft_no != ni->mft_no) {
|
while ( ctx->ntfs_ino->mft_no != ni->mft_no )
|
||||||
|
{
|
||||||
retry:
|
retry:
|
||||||
if ( ntfs_attr_position( AT_UNUSED, ctx ) )
|
if ( ntfs_attr_position( AT_UNUSED, ctx ) )
|
||||||
goto put_err_out;
|
goto put_err_out;
|
||||||
@ -1298,14 +1409,16 @@ retry:
|
|||||||
|
|
||||||
record_size = le32_to_cpu( ctx->attr->length );
|
record_size = le32_to_cpu( ctx->attr->length );
|
||||||
|
|
||||||
if (ntfs_attr_record_move_away(ctx, 0)) {
|
if ( ntfs_attr_record_move_away( ctx, 0 ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to move out attribute #2" );
|
ntfs_log_perror( "Failed to move out attribute #2" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
freed += record_size;
|
freed += record_size;
|
||||||
|
|
||||||
/* Check whether we are done. */
|
/* Check whether we are done. */
|
||||||
if (size <= freed) {
|
if ( size <= freed )
|
||||||
|
{
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1339,7 +1452,8 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
|
|||||||
{
|
{
|
||||||
ntfs_time now;
|
ntfs_time now;
|
||||||
|
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfs_log_error( "%s(): Invalid arguments.\n", __FUNCTION__ );
|
ntfs_log_error( "%s(): Invalid arguments.\n", __FUNCTION__ );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1377,7 +1491,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
|
|||||||
int len, ret = 0;
|
int len, ret = 0;
|
||||||
ntfschar *ustr;
|
ntfschar *ustr;
|
||||||
|
|
||||||
if (!attr) {
|
if ( !attr )
|
||||||
|
{
|
||||||
ntfs_log_error( "Invalid argument.\n" );
|
ntfs_log_error( "Invalid argument.\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -1389,7 +1504,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
|
|||||||
if ( attr->type != AT_DATA )
|
if ( attr->type != AT_DATA )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) {
|
if ( ( ustr = ntfs_str2ucs( "$Bad", &len ) ) == NULL )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Couldn't convert '$Bad' to Unicode" );
|
ntfs_log_perror( "Couldn't convert '$Bad' to Unicode" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1425,32 +1541,40 @@ int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size)
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||||
if (ctx) {
|
if ( ctx )
|
||||||
|
{
|
||||||
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
|
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION, AT_UNNAMED,
|
||||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
0, CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to get standard info (inode %lld)",
|
ntfs_log_perror( "Failed to get standard info (inode %lld)",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
||||||
le16_to_cpu( ctx->attr->value_offset ) );
|
le16_to_cpu( ctx->attr->value_offset ) );
|
||||||
if (value && (size >= 8)) {
|
if ( value && ( size >= 8 ) )
|
||||||
|
{
|
||||||
times = ( u64* )value;
|
times = ( u64* )value;
|
||||||
times[0] = le64_to_cpu( std_info->creation_time );
|
times[0] = le64_to_cpu( std_info->creation_time );
|
||||||
ret = 8;
|
ret = 8;
|
||||||
if (size >= 16) {
|
if ( size >= 16 )
|
||||||
|
{
|
||||||
times[1] = le64_to_cpu( std_info->last_data_change_time );
|
times[1] = le64_to_cpu( std_info->last_data_change_time );
|
||||||
ret = 16;
|
ret = 16;
|
||||||
}
|
}
|
||||||
if (size >= 24) {
|
if ( size >= 24 )
|
||||||
|
{
|
||||||
times[2] = le64_to_cpu( std_info->last_access_time );
|
times[2] = le64_to_cpu( std_info->last_access_time );
|
||||||
ret = 24;
|
ret = 24;
|
||||||
}
|
}
|
||||||
if (size >= 32) {
|
if ( size >= 32 )
|
||||||
|
{
|
||||||
times[3] = le64_to_cpu( std_info->last_mft_change_time );
|
times[3] = le64_to_cpu( std_info->last_mft_change_time );
|
||||||
ret = 32;
|
ret = 32;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
if (!size)
|
else if ( !size )
|
||||||
ret = 32;
|
ret = 32;
|
||||||
else
|
else
|
||||||
ret = -ERANGE;
|
ret = -ERANGE;
|
||||||
@ -1486,18 +1610,23 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
if ((size >= 8) && !(flags & XATTR_CREATE)) {
|
if ( ( size >= 8 ) && !( flags & XATTR_CREATE ) )
|
||||||
|
{
|
||||||
times = ( const u64* )value;
|
times = ( const u64* )value;
|
||||||
now = ntfs_current_time();
|
now = ntfs_current_time();
|
||||||
/* update the standard information attribute */
|
/* update the standard information attribute */
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||||
if (ctx) {
|
if ( ctx )
|
||||||
|
{
|
||||||
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION,
|
if ( ntfs_attr_lookup( AT_STANDARD_INFORMATION,
|
||||||
AT_UNNAMED, 0, CASE_SENSITIVE,
|
AT_UNNAMED, 0, CASE_SENSITIVE,
|
||||||
0, NULL, 0, ctx)) {
|
0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to get standard info (inode %lld)",
|
ntfs_log_perror( "Failed to get standard info (inode %lld)",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
std_info = ( STANDARD_INFORMATION * )( ( u8 * )ctx->attr +
|
||||||
le16_to_cpu( ctx->attr->value_offset ) );
|
le16_to_cpu( ctx->attr->value_offset ) );
|
||||||
/*
|
/*
|
||||||
@ -1512,12 +1641,14 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
std_info->creation_time = cpu_to_le64( times[0] );
|
std_info->creation_time = cpu_to_le64( times[0] );
|
||||||
ni->creation_time
|
ni->creation_time
|
||||||
= std_info->creation_time;
|
= std_info->creation_time;
|
||||||
if (size >= 16) {
|
if ( size >= 16 )
|
||||||
|
{
|
||||||
std_info->last_data_change_time = cpu_to_le64( times[1] );
|
std_info->last_data_change_time = cpu_to_le64( times[1] );
|
||||||
ni->last_data_change_time
|
ni->last_data_change_time
|
||||||
= std_info->last_data_change_time;
|
= std_info->last_data_change_time;
|
||||||
}
|
}
|
||||||
if (size >= 24) {
|
if ( size >= 24 )
|
||||||
|
{
|
||||||
std_info->last_access_time = cpu_to_le64( times[2] );
|
std_info->last_access_time = cpu_to_le64( times[2] );
|
||||||
ni->last_access_time
|
ni->last_access_time
|
||||||
= std_info->last_access_time;
|
= std_info->last_access_time;
|
||||||
@ -1532,7 +1663,8 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
cnt = 0;
|
cnt = 0;
|
||||||
while ( !ntfs_attr_lookup( AT_FILE_NAME,
|
while ( !ntfs_attr_lookup( AT_FILE_NAME,
|
||||||
AT_UNNAMED, 0, CASE_SENSITIVE,
|
AT_UNNAMED, 0, CASE_SENSITIVE,
|
||||||
0, NULL, 0, ctx)) {
|
0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
fn = ( FILE_NAME_ATTR* )( ( u8 * )ctx->attr +
|
fn = ( FILE_NAME_ATTR* )( ( u8 * )ctx->attr +
|
||||||
le16_to_cpu( ctx->attr->value_offset ) );
|
le16_to_cpu( ctx->attr->value_offset ) );
|
||||||
fn->creation_time
|
fn->creation_time
|
||||||
@ -1548,15 +1680,16 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
}
|
}
|
||||||
if ( cnt )
|
if ( cnt )
|
||||||
ret = 0;
|
ret = 0;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to get file names (inode %lld)",
|
ntfs_log_perror( "Failed to get file names (inode %lld)",
|
||||||
( long long )ni->mft_no );
|
( long long )ni->mft_no );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
if (size < 8)
|
else if ( size < 8 )
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
else
|
else
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
|
@ -40,7 +40,8 @@ typedef struct _ntfs_inode ntfs_inode;
|
|||||||
* Defined bits for the state field in the ntfs_inode structure.
|
* Defined bits for the state field in the ntfs_inode structure.
|
||||||
* (f) = files only, (d) = directories only
|
* (f) = files only, (d) = directories only
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||||
|
|
||||||
/* The NI_AttrList* tests only make sense for base inodes. */
|
/* The NI_AttrList* tests only make sense for base inodes. */
|
||||||
@ -103,7 +104,8 @@ typedef enum {
|
|||||||
* It is just used as an extension to the fields already provided in the VFS
|
* It is just used as an extension to the fields already provided in the VFS
|
||||||
* inode.
|
* inode.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_inode {
|
struct _ntfs_inode
|
||||||
|
{
|
||||||
u64 mft_no; /* Inode / mft record number. */
|
u64 mft_no; /* Inode / mft record number. */
|
||||||
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
||||||
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
||||||
@ -122,7 +124,8 @@ struct _ntfs_inode {
|
|||||||
s32 nr_extents; /* For a base mft record, the number of
|
s32 nr_extents; /* For a base mft record, the number of
|
||||||
attached extent inodes (0 if none), for
|
attached extent inodes (0 if none), for
|
||||||
extent records this is -1. */
|
extent records this is -1. */
|
||||||
union { /* This union is only used if nr_extents != 0. */
|
union /* This union is only used if nr_extents != 0. */
|
||||||
|
{
|
||||||
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
||||||
ntfs inodes of the extent mft
|
ntfs inodes of the extent mft
|
||||||
records belonging to this base
|
records belonging to this base
|
||||||
@ -166,7 +169,8 @@ struct _ntfs_inode {
|
|||||||
le64 usn;
|
le64 usn;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NTFS_UPDATE_ATIME = 1 << 0,
|
NTFS_UPDATE_ATIME = 1 << 0,
|
||||||
NTFS_UPDATE_MTIME = 1 << 1,
|
NTFS_UPDATE_MTIME = 1 << 1,
|
||||||
NTFS_UPDATE_CTIME = 1 << 2,
|
NTFS_UPDATE_CTIME = 1 << 2,
|
||||||
|
@ -46,7 +46,8 @@
|
|||||||
/**
|
/**
|
||||||
* struct BIOS_PARAMETER_BLOCK - BIOS parameter block (bpb) structure.
|
* struct BIOS_PARAMETER_BLOCK - BIOS parameter block (bpb) structure.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u16 bytes_per_sector; /* Size of a sector in bytes. */
|
u16 bytes_per_sector; /* Size of a sector in bytes. */
|
||||||
u8 sectors_per_cluster; /* Size of a cluster in sectors. */
|
u8 sectors_per_cluster; /* Size of a cluster in sectors. */
|
||||||
u16 reserved_sectors; /* zero */
|
u16 reserved_sectors; /* zero */
|
||||||
@ -67,7 +68,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* struct NTFS_BOOT_SECTOR - NTFS boot sector structure.
|
* struct NTFS_BOOT_SECTOR - NTFS boot sector structure.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 jump[3]; /* Irrelevant (jump to boot up code).*/
|
u8 jump[3]; /* Irrelevant (jump to boot up code).*/
|
||||||
u64 oem_id; /* Magic "NTFS ". */
|
u64 oem_id; /* Magic "NTFS ". */
|
||||||
/*0x0b*/BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */
|
/*0x0b*/BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */
|
||||||
@ -100,7 +102,8 @@ typedef struct {
|
|||||||
* Magic identifiers present at the beginning of all ntfs record containing
|
* Magic identifiers present at the beginning of all ntfs record containing
|
||||||
* records (like mft records for example).
|
* records (like mft records for example).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/* Found in $MFT/$DATA. */
|
/* Found in $MFT/$DATA. */
|
||||||
magic_FILE = const_cpu_to_le32( 0x454c4946 ), /* Mft entry. */
|
magic_FILE = const_cpu_to_le32( 0x454c4946 ), /* Mft entry. */
|
||||||
magic_INDX = const_cpu_to_le32( 0x58444e49 ), /* Index buffer. */
|
magic_INDX = const_cpu_to_le32( 0x58444e49 ), /* Index buffer. */
|
||||||
@ -182,7 +185,8 @@ typedef enum {
|
|||||||
* This formula can be used as a consistency check in that usa_ofs +
|
* This formula can be used as a consistency check in that usa_ofs +
|
||||||
* (usa_count * 2) has to be less than or equal to 510.
|
* (usa_count * 2) has to be less than or equal to 510.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
NTFS_RECORD_TYPES magic;/* A four-byte magic identifying the
|
NTFS_RECORD_TYPES magic;/* A four-byte magic identifying the
|
||||||
record type and/or status. */
|
record type and/or status. */
|
||||||
u16 usa_ofs; /* Offset to the Update Sequence Array (usa)
|
u16 usa_ofs; /* Offset to the Update Sequence Array (usa)
|
||||||
@ -201,7 +205,8 @@ typedef struct {
|
|||||||
* mft records. Also, the sequence number for each of the system files is
|
* mft records. Also, the sequence number for each of the system files is
|
||||||
* always equal to their mft record number and it is never modified.
|
* always equal to their mft record number and it is never modified.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
FILE_MFT = 0, /* Master file table (mft). Data attribute
|
FILE_MFT = 0, /* Master file table (mft). Data attribute
|
||||||
contains the entries and bitmap attribute
|
contains the entries and bitmap attribute
|
||||||
records which ones are in use (bit==1). */
|
records which ones are in use (bit==1). */
|
||||||
@ -254,7 +259,8 @@ typedef enum {
|
|||||||
* index, that means an INDEX_ROOT and an INDEX_ALLOCATION with a name other
|
* index, that means an INDEX_ROOT and an INDEX_ALLOCATION with a name other
|
||||||
* than "$I30". It is unknown if it is limited to metadata files only.
|
* than "$I30". It is unknown if it is limited to metadata files only.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
MFT_RECORD_IN_USE = const_cpu_to_le16( 0x0001 ),
|
MFT_RECORD_IN_USE = const_cpu_to_le16( 0x0001 ),
|
||||||
MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16( 0x0002 ),
|
MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16( 0x0002 ),
|
||||||
MFT_RECORD_IS_4 = const_cpu_to_le16( 0x0004 ),
|
MFT_RECORD_IS_4 = const_cpu_to_le16( 0x0004 ),
|
||||||
@ -335,7 +341,8 @@ typedef u64 MFT_REF;
|
|||||||
* in that it only consists of the attribute type code AT_END and none of the
|
* in that it only consists of the attribute type code AT_END and none of the
|
||||||
* other members of the attribute structure are present.
|
* other members of the attribute structure are present.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
|
NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
|
||||||
@ -409,7 +416,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* This is the version without the NTFS 3.1+ specific fields.
|
* This is the version without the NTFS 3.1+ specific fields.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
|
NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
|
||||||
@ -486,7 +494,8 @@ typedef struct {
|
|||||||
* enum exchanging AT_ for the dollar sign ($). If that isn't a revealing
|
* enum exchanging AT_ for the dollar sign ($). If that isn't a revealing
|
||||||
* choice of symbol... (-;
|
* choice of symbol... (-;
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
AT_UNUSED = const_cpu_to_le32( 0 ),
|
AT_UNUSED = const_cpu_to_le32( 0 ),
|
||||||
AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10 ),
|
AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10 ),
|
||||||
AT_ATTRIBUTE_LIST = const_cpu_to_le32( 0x20 ),
|
AT_ATTRIBUTE_LIST = const_cpu_to_le32( 0x20 ),
|
||||||
@ -545,7 +554,8 @@ typedef enum {
|
|||||||
* the 2nd object_id. If the first u32 values of both object_ids were
|
* the 2nd object_id. If the first u32 values of both object_ids were
|
||||||
* equal then the second u32 values would be compared, etc.
|
* equal then the second u32 values would be compared, etc.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
COLLATION_BINARY = const_cpu_to_le32( 0 ), /* Collate by binary
|
COLLATION_BINARY = const_cpu_to_le32( 0 ), /* Collate by binary
|
||||||
compare where the first byte is most
|
compare where the first byte is most
|
||||||
significant. */
|
significant. */
|
||||||
@ -573,7 +583,8 @@ typedef enum {
|
|||||||
* name attribute has this flag set and this is the only attribute indexed in
|
* name attribute has this flag set and this is the only attribute indexed in
|
||||||
* NT4.
|
* NT4.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ATTR_DEF_INDEXABLE = const_cpu_to_le32( 0x02 ), /* Attribute can be
|
ATTR_DEF_INDEXABLE = const_cpu_to_le32( 0x02 ), /* Attribute can be
|
||||||
indexed. */
|
indexed. */
|
||||||
ATTR_DEF_MULTIPLE = const_cpu_to_le32( 0x04 ), /* Attribute type
|
ATTR_DEF_MULTIPLE = const_cpu_to_le32( 0x04 ), /* Attribute type
|
||||||
@ -611,9 +622,11 @@ typedef enum {
|
|||||||
* attribute can be resident/non-resident and possibly other things, but the
|
* attribute can be resident/non-resident and possibly other things, but the
|
||||||
* actual bits are unknown.
|
* actual bits are unknown.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*hex ofs*/
|
/*hex ofs*/
|
||||||
/* 0*/ ntfschar name[0x40]; /* Unicode name of the attribute. Zero
|
/* 0*/
|
||||||
|
ntfschar name[0x40]; /* Unicode name of the attribute. Zero
|
||||||
terminated. */
|
terminated. */
|
||||||
/* 80*/ ATTR_TYPES type; /* Type of the attribute. */
|
/* 80*/ ATTR_TYPES type; /* Type of the attribute. */
|
||||||
/* 84*/ u32 display_rule; /* Default display rule.
|
/* 84*/ u32 display_rule; /* Default display rule.
|
||||||
@ -628,7 +641,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* enum ATTR_FLAGS - Attribute flags (16-bit).
|
* enum ATTR_FLAGS - Attribute flags (16-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ATTR_IS_COMPRESSED = const_cpu_to_le16( 0x0001 ),
|
ATTR_IS_COMPRESSED = const_cpu_to_le16( 0x0001 ),
|
||||||
ATTR_COMPRESSION_MASK = const_cpu_to_le16( 0x00ff ), /* Compression
|
ATTR_COMPRESSION_MASK = const_cpu_to_le16( 0x00ff ), /* Compression
|
||||||
method mask. Also, first
|
method mask. Also, first
|
||||||
@ -707,7 +721,8 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* enum RESIDENT_ATTR_FLAGS - Flags of resident attributes (8-bit).
|
* enum RESIDENT_ATTR_FLAGS - Flags of resident attributes (8-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index
|
RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index
|
||||||
(has implications for deleting and
|
(has implications for deleting and
|
||||||
modifying the attribute). */
|
modifying the attribute). */
|
||||||
@ -718,9 +733,11 @@ typedef enum {
|
|||||||
*
|
*
|
||||||
* Always aligned to 8-byte boundary.
|
* Always aligned to 8-byte boundary.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0*/ ATTR_TYPES type; /* The (32-bit) type of the attribute. */
|
/* 0*/
|
||||||
|
ATTR_TYPES type; /* The (32-bit) type of the attribute. */
|
||||||
/* 4*/ u32 length; /* Byte size of the resident part of the
|
/* 4*/ u32 length; /* Byte size of the resident part of the
|
||||||
attribute (aligned to 8-byte boundary).
|
attribute (aligned to 8-byte boundary).
|
||||||
Used to get to the next attribute. */
|
Used to get to the next attribute. */
|
||||||
@ -742,10 +759,13 @@ typedef struct {
|
|||||||
number is unique within this mft record (see
|
number is unique within this mft record (see
|
||||||
MFT_RECORD/next_attribute_instance notes
|
MFT_RECORD/next_attribute_instance notes
|
||||||
above for more details). */
|
above for more details). */
|
||||||
/* 16*/ union {
|
/* 16*/ union
|
||||||
|
{
|
||||||
/* Resident attributes. */
|
/* Resident attributes. */
|
||||||
struct {
|
struct
|
||||||
/* 16 */ u32 value_length; /* Byte size of attribute value. */
|
{
|
||||||
|
/* 16 */
|
||||||
|
u32 value_length; /* Byte size of attribute value. */
|
||||||
/* 20 */ u16 value_offset; /* Byte offset of the attribute
|
/* 20 */ u16 value_offset; /* Byte offset of the attribute
|
||||||
value from the start of the
|
value from the start of the
|
||||||
attribute record. When creating,
|
attribute record. When creating,
|
||||||
@ -761,8 +781,10 @@ typedef struct {
|
|||||||
a resident attribute. */
|
a resident attribute. */
|
||||||
} __attribute__( ( __packed__ ) );
|
} __attribute__( ( __packed__ ) );
|
||||||
/* Non-resident attributes. */
|
/* Non-resident attributes. */
|
||||||
struct {
|
struct
|
||||||
/* 16*/ VCN lowest_vcn; /* Lowest valid virtual cluster number
|
{
|
||||||
|
/* 16*/
|
||||||
|
VCN lowest_vcn; /* Lowest valid virtual cluster number
|
||||||
for this portion of the attribute value or
|
for this portion of the attribute value or
|
||||||
0 if this is the only extent (usually the
|
0 if this is the only extent (usually the
|
||||||
case). - Only when an attribute list is used
|
case). - Only when an attribute list is used
|
||||||
@ -825,7 +847,8 @@ typedef ATTR_RECORD ATTR_REC;
|
|||||||
/**
|
/**
|
||||||
* enum FILE_ATTR_FLAGS - File attribute flags (32-bit).
|
* enum FILE_ATTR_FLAGS - File attribute flags (32-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* These flags are only present in the STANDARD_INFORMATION attribute
|
* These flags are only present in the STANDARD_INFORMATION attribute
|
||||||
* (in the field file_attributes).
|
* (in the field file_attributes).
|
||||||
@ -905,9 +928,11 @@ typedef enum {
|
|||||||
* correct by practical experimentation on Windows NT4 SP6a and is hence
|
* correct by practical experimentation on Windows NT4 SP6a and is hence
|
||||||
* assumed to be the one and only correct interpretation.
|
* assumed to be the one and only correct interpretation.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0*/ s64 creation_time; /* Time file was created. Updated when
|
/* 0*/
|
||||||
|
s64 creation_time; /* Time file was created. Updated when
|
||||||
a filename is changed(?). */
|
a filename is changed(?). */
|
||||||
/* 8*/ s64 last_data_change_time; /* Time the data attribute was last
|
/* 8*/ s64 last_data_change_time; /* Time the data attribute was last
|
||||||
modified. */
|
modified. */
|
||||||
@ -922,16 +947,20 @@ typedef struct {
|
|||||||
last access times updates can be
|
last access times updates can be
|
||||||
disabled altogether for speed. */
|
disabled altogether for speed. */
|
||||||
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
|
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
|
||||||
/* 36*/ union {
|
/* 36*/ union
|
||||||
|
{
|
||||||
/* NTFS 1.2 (and previous, presumably) */
|
/* NTFS 1.2 (and previous, presumably) */
|
||||||
struct {
|
struct
|
||||||
/* 36 */ u8 reserved12[12]; /* Reserved/alignment to 8-byte
|
{
|
||||||
|
/* 36 */
|
||||||
|
u8 reserved12[12]; /* Reserved/alignment to 8-byte
|
||||||
boundary. */
|
boundary. */
|
||||||
/* 48 */ void *v1_end[0]; /* Marker for offsetof(). */
|
/* 48 */ void *v1_end[0]; /* Marker for offsetof(). */
|
||||||
} __attribute__( ( __packed__ ) );
|
} __attribute__( ( __packed__ ) );
|
||||||
/* sizeof() = 48 bytes */
|
/* sizeof() = 48 bytes */
|
||||||
/* NTFS 3.0 */
|
/* NTFS 3.0 */
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If a volume has been upgraded from a previous NTFS version, then these
|
* If a volume has been upgraded from a previous NTFS version, then these
|
||||||
* fields are present only if the file has been accessed since the upgrade.
|
* fields are present only if the file has been accessed since the upgrade.
|
||||||
@ -951,7 +980,8 @@ typedef struct {
|
|||||||
* views that as a corruption, assuming that it behaves like this for all
|
* views that as a corruption, assuming that it behaves like this for all
|
||||||
* attributes.
|
* attributes.
|
||||||
*/
|
*/
|
||||||
/* 36*/ u32 maximum_versions; /* Maximum allowed versions for
|
/* 36*/
|
||||||
|
u32 maximum_versions; /* Maximum allowed versions for
|
||||||
file. Zero if version numbering is disabled. */
|
file. Zero if version numbering is disabled. */
|
||||||
/* 40*/ u32 version_number; /* This file's version (if any).
|
/* 40*/ u32 version_number; /* This file's version (if any).
|
||||||
Set to zero if maximum_versions is zero. */
|
Set to zero if maximum_versions is zero. */
|
||||||
@ -1016,9 +1046,11 @@ typedef struct {
|
|||||||
* NTFS 3.0 volumes).
|
* NTFS 3.0 volumes).
|
||||||
* - There are many named streams.
|
* - There are many named streams.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0*/ ATTR_TYPES type; /* Type of referenced attribute. */
|
/* 0*/
|
||||||
|
ATTR_TYPES type; /* Type of referenced attribute. */
|
||||||
/* 4*/ u16 length; /* Byte size of this entry. */
|
/* 4*/ u16 length; /* Byte size of this entry. */
|
||||||
/* 6*/ u8 name_length; /* Size in Unicode chars of the name of the
|
/* 6*/ u8 name_length; /* Size in Unicode chars of the name of the
|
||||||
attribute or 0 if unnamed. */
|
attribute or 0 if unnamed. */
|
||||||
@ -1057,7 +1089,8 @@ typedef struct {
|
|||||||
* enum FILE_NAME_TYPE_FLAGS - Possible namespaces for filenames in ntfs.
|
* enum FILE_NAME_TYPE_FLAGS - Possible namespaces for filenames in ntfs.
|
||||||
* (8-bit).
|
* (8-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
FILE_NAME_POSIX = 0x00,
|
FILE_NAME_POSIX = 0x00,
|
||||||
/* This is the largest namespace. It is case sensitive and
|
/* This is the largest namespace. It is case sensitive and
|
||||||
allows all Unicode characters except for: '\0' and '/'.
|
allows all Unicode characters except for: '\0' and '/'.
|
||||||
@ -1093,9 +1126,11 @@ typedef enum {
|
|||||||
* correct by practical experimentation on Windows NT4 SP6a and is hence
|
* correct by practical experimentation on Windows NT4 SP6a and is hence
|
||||||
* assumed to be the one and only correct interpretation.
|
* assumed to be the one and only correct interpretation.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*hex ofs*/
|
/*hex ofs*/
|
||||||
/* 0*/ MFT_REF parent_directory; /* Directory this filename is
|
/* 0*/
|
||||||
|
MFT_REF parent_directory; /* Directory this filename is
|
||||||
referenced from. */
|
referenced from. */
|
||||||
/* 8*/ s64 creation_time; /* Time file was created. */
|
/* 8*/ s64 creation_time; /* Time file was created. */
|
||||||
/* 10*/ s64 last_data_change_time; /* Time the data attribute was last
|
/* 10*/ s64 last_data_change_time; /* Time the data attribute was last
|
||||||
@ -1116,9 +1151,13 @@ typedef struct {
|
|||||||
/* 30*/ s64 data_size; /* Byte size of actual data in data
|
/* 30*/ s64 data_size; /* Byte size of actual data in data
|
||||||
attribute. */
|
attribute. */
|
||||||
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
|
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
|
||||||
/* 3c*/ union {
|
/* 3c*/ union
|
||||||
/* 3c*/ struct {
|
{
|
||||||
/* 3c*/ u16 packed_ea_size; /* Size of the buffer needed to
|
/* 3c*/
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* 3c*/
|
||||||
|
u16 packed_ea_size; /* Size of the buffer needed to
|
||||||
pack the extended attributes
|
pack the extended attributes
|
||||||
(EAs), if such are present.*/
|
(EAs), if such are present.*/
|
||||||
/* 3e*/ u16 reserved; /* Reserved for alignment. */
|
/* 3e*/ u16 reserved; /* Reserved for alignment. */
|
||||||
@ -1146,7 +1185,8 @@ typedef struct {
|
|||||||
* Example of a GUID:
|
* Example of a GUID:
|
||||||
* 1F010768-5A73-BC91-0010-A52216A7227B
|
* 1F010768-5A73-BC91-0010-A52216A7227B
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 data1; /* The first eight hexadecimal digits of the GUID. */
|
u32 data1; /* The first eight hexadecimal digits of the GUID. */
|
||||||
u16 data2; /* The first group of four hexadecimal digits. */
|
u16 data2; /* The first group of four hexadecimal digits. */
|
||||||
u16 data3; /* The second group of four hexadecimal digits. */
|
u16 data3; /* The second group of four hexadecimal digits. */
|
||||||
@ -1168,11 +1208,14 @@ typedef struct {
|
|||||||
* equals the object_id. Optional (i.e. can be zero).
|
* equals the object_id. Optional (i.e. can be zero).
|
||||||
* domain_id - Reserved (always zero).
|
* domain_id - Reserved (always zero).
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
MFT_REF mft_reference; /* Mft record containing the object_id in
|
MFT_REF mft_reference; /* Mft record containing the object_id in
|
||||||
the index entry key. */
|
the index entry key. */
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
GUID birth_volume_id;
|
GUID birth_volume_id;
|
||||||
GUID birth_object_id;
|
GUID birth_object_id;
|
||||||
GUID domain_id;
|
GUID domain_id;
|
||||||
@ -1186,7 +1229,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* NOTE: Always resident.
|
* NOTE: Always resident.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
GUID object_id; /* Unique id assigned to the
|
GUID object_id; /* Unique id assigned to the
|
||||||
file.*/
|
file.*/
|
||||||
/* The following fields are optional. The attribute value size is 16
|
/* The following fields are optional. The attribute value size is 16
|
||||||
@ -1196,8 +1240,10 @@ typedef struct {
|
|||||||
when the fields are missing here, it is well possible that they are
|
when the fields are missing here, it is well possible that they are
|
||||||
to be found within the $Extend/$ObjId system file indexed under the
|
to be found within the $Extend/$ObjId system file indexed under the
|
||||||
above object_id. */
|
above object_id. */
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
GUID birth_volume_id; /* Unique id of volume on which
|
GUID birth_volume_id; /* Unique id of volume on which
|
||||||
the file was first created.*/
|
the file was first created.*/
|
||||||
GUID birth_object_id; /* Unique id of file when it was
|
GUID birth_object_id; /* Unique id of file when it was
|
||||||
@ -1215,7 +1261,8 @@ typedef struct {
|
|||||||
* The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
|
* The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
|
||||||
* the SID structure (see below).
|
* the SID structure (see below).
|
||||||
*/
|
*/
|
||||||
typedef enum { /* SID string prefix. */
|
typedef enum /* SID string prefix. */
|
||||||
|
{
|
||||||
SECURITY_NULL_SID_AUTHORITY = {0, 0, 0, 0, 0, 0}, /* S-1-0 */
|
SECURITY_NULL_SID_AUTHORITY = {0, 0, 0, 0, 0, 0}, /* S-1-0 */
|
||||||
SECURITY_WORLD_SID_AUTHORITY = {0, 0, 0, 0, 0, 1}, /* S-1-1 */
|
SECURITY_WORLD_SID_AUTHORITY = {0, 0, 0, 0, 0, 1}, /* S-1-1 */
|
||||||
SECURITY_LOCAL_SID_AUTHORITY = {0, 0, 0, 0, 0, 2}, /* S-1-2 */
|
SECURITY_LOCAL_SID_AUTHORITY = {0, 0, 0, 0, 0, 2}, /* S-1-2 */
|
||||||
@ -1237,7 +1284,8 @@ typedef enum { /* SID string prefix. */
|
|||||||
* made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and
|
* made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and
|
||||||
* the relative identifier SECURITY_CREATOR_OWNER_RID (0).
|
* the relative identifier SECURITY_CREATOR_OWNER_RID (0).
|
||||||
*/
|
*/
|
||||||
typedef enum { /* Identifier authority. */
|
typedef enum /* Identifier authority. */
|
||||||
|
{
|
||||||
SECURITY_NULL_RID = 0, /* S-1-0 */
|
SECURITY_NULL_RID = 0, /* S-1-0 */
|
||||||
SECURITY_WORLD_RID = 0, /* S-1-1 */
|
SECURITY_WORLD_RID = 0, /* S-1-1 */
|
||||||
SECURITY_LOCAL_RID = 0, /* S-1-2 */
|
SECURITY_LOCAL_RID = 0, /* S-1-2 */
|
||||||
@ -1349,8 +1397,10 @@ typedef enum { /* Identifier authority. */
|
|||||||
*
|
*
|
||||||
* NOTE: This is stored as a big endian number.
|
* NOTE: This is stored as a big endian number.
|
||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
u16 high_part; /* High 16-bits. */
|
u16 high_part; /* High 16-bits. */
|
||||||
u32 low_part; /* Low 32-bits. */
|
u32 low_part; /* Low 32-bits. */
|
||||||
} __attribute__( ( __packed__ ) );
|
} __attribute__( ( __packed__ ) );
|
||||||
@ -1385,7 +1435,8 @@ typedef union {
|
|||||||
* sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID
|
* sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID
|
||||||
* sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS
|
* sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 revision;
|
u8 revision;
|
||||||
u8 sub_authority_count;
|
u8 sub_authority_count;
|
||||||
SID_IDENTIFIER_AUTHORITY identifier_authority;
|
SID_IDENTIFIER_AUTHORITY identifier_authority;
|
||||||
@ -1395,7 +1446,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* enum SID_CONSTANTS - Current constants for SIDs.
|
* enum SID_CONSTANTS - Current constants for SIDs.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
SID_REVISION = 1, /* Current revision level. */
|
SID_REVISION = 1, /* Current revision level. */
|
||||||
SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */
|
SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */
|
||||||
SID_RECOMMENDED_SUB_AUTHORITIES = 1, /* Will change to around 6 in
|
SID_RECOMMENDED_SUB_AUTHORITIES = 1, /* Will change to around 6 in
|
||||||
@ -1405,7 +1457,8 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* enum ACE_TYPES - The predefined ACE types (8-bit, see below).
|
* enum ACE_TYPES - The predefined ACE types (8-bit, see below).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ACCESS_MIN_MS_ACE_TYPE = 0,
|
ACCESS_MIN_MS_ACE_TYPE = 0,
|
||||||
ACCESS_ALLOWED_ACE_TYPE = 0,
|
ACCESS_ALLOWED_ACE_TYPE = 0,
|
||||||
ACCESS_DENIED_ACE_TYPE = 1,
|
ACCESS_DENIED_ACE_TYPE = 1,
|
||||||
@ -1440,7 +1493,8 @@ typedef enum {
|
|||||||
* FAILED_ACCESS_ACE_FLAG is only used with system audit and alarm ACE types
|
* FAILED_ACCESS_ACE_FLAG is only used with system audit and alarm ACE types
|
||||||
* to indicate that a message is generated (in Windows!) for failed accesses.
|
* to indicate that a message is generated (in Windows!) for failed accesses.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/* The inheritance flags. */
|
/* The inheritance flags. */
|
||||||
OBJECT_INHERIT_ACE = 0x01,
|
OBJECT_INHERIT_ACE = 0x01,
|
||||||
CONTAINER_INHERIT_ACE = 0x02,
|
CONTAINER_INHERIT_ACE = 0x02,
|
||||||
@ -1467,7 +1521,8 @@ typedef enum {
|
|||||||
* which specifies the type and size of the ACE. The format of the subsequent
|
* which specifies the type and size of the ACE. The format of the subsequent
|
||||||
* data depends on the ACE type.
|
* data depends on the ACE type.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
ACE_TYPES type; /* Type of the ACE. */
|
ACE_TYPES type; /* Type of the ACE. */
|
||||||
ACE_FLAGS flags; /* Flags describing the ACE. */
|
ACE_FLAGS flags; /* Flags describing the ACE. */
|
||||||
u16 size; /* Size in bytes of the ACE. */
|
u16 size; /* Size in bytes of the ACE. */
|
||||||
@ -1478,7 +1533,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* Defines the access rights.
|
* Defines the access rights.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* The specific rights (bits 0 to 15). Depend on the type of the
|
* The specific rights (bits 0 to 15). Depend on the type of the
|
||||||
* object being secured by the ACE.
|
* object being secured by the ACE.
|
||||||
@ -1616,7 +1672,8 @@ typedef enum {
|
|||||||
*
|
*
|
||||||
* FIXME: What exactly is this and what is it for? (AIA)
|
* FIXME: What exactly is this and what is it for? (AIA)
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
ACCESS_MASK generic_read;
|
ACCESS_MASK generic_read;
|
||||||
ACCESS_MASK generic_write;
|
ACCESS_MASK generic_write;
|
||||||
ACCESS_MASK generic_execute;
|
ACCESS_MASK generic_execute;
|
||||||
@ -1632,7 +1689,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
|
* ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
ACE_TYPES type; /* Type of the ACE. */
|
ACE_TYPES type; /* Type of the ACE. */
|
||||||
ACE_FLAGS flags; /* Flags describing the ACE. */
|
ACE_FLAGS flags; /* Flags describing the ACE. */
|
||||||
@ -1646,7 +1704,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* enum OBJECT_ACE_FLAGS - The object ACE flags (32-bit).
|
* enum OBJECT_ACE_FLAGS - The object ACE flags (32-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 1 ),
|
ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 1 ),
|
||||||
ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 2 ),
|
ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32( 2 ),
|
||||||
} OBJECT_ACE_FLAGS;
|
} OBJECT_ACE_FLAGS;
|
||||||
@ -1654,7 +1713,8 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* struct ACCESS_ALLOWED_OBJECT_ACE -
|
* struct ACCESS_ALLOWED_OBJECT_ACE -
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
ACE_TYPES type; /* Type of the ACE. */
|
ACE_TYPES type; /* Type of the ACE. */
|
||||||
ACE_FLAGS flags; /* Flags describing the ACE. */
|
ACE_FLAGS flags; /* Flags describing the ACE. */
|
||||||
@ -1678,7 +1738,8 @@ typedef struct {
|
|||||||
* zero or more access control entries (ACEs). The ACL as well as each ACE
|
* zero or more access control entries (ACEs). The ACL as well as each ACE
|
||||||
* are aligned on 4-byte boundaries.
|
* are aligned on 4-byte boundaries.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 revision; /* Revision of this ACL. */
|
u8 revision; /* Revision of this ACL. */
|
||||||
u8 alignment1;
|
u8 alignment1;
|
||||||
u16 size; /* Allocated space in bytes for ACL. Includes this
|
u16 size; /* Allocated space in bytes for ACL. Includes this
|
||||||
@ -1691,7 +1752,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* enum ACL_CONSTANTS - Current constants for ACLs.
|
* enum ACL_CONSTANTS - Current constants for ACLs.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/* Current revision. */
|
/* Current revision. */
|
||||||
ACL_REVISION = 2,
|
ACL_REVISION = 2,
|
||||||
ACL_REVISION_DS = 4,
|
ACL_REVISION_DS = 4,
|
||||||
@ -1754,7 +1816,8 @@ typedef enum {
|
|||||||
* and all pointer fields are expressed as offsets from the
|
* and all pointer fields are expressed as offsets from the
|
||||||
* beginning of the security descriptor.
|
* beginning of the security descriptor.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
SE_OWNER_DEFAULTED = const_cpu_to_le16( 0x0001 ),
|
SE_OWNER_DEFAULTED = const_cpu_to_le16( 0x0001 ),
|
||||||
SE_GROUP_DEFAULTED = const_cpu_to_le16( 0x0002 ),
|
SE_GROUP_DEFAULTED = const_cpu_to_le16( 0x0002 ),
|
||||||
SE_DACL_PRESENT = const_cpu_to_le16( 0x0004 ),
|
SE_DACL_PRESENT = const_cpu_to_le16( 0x0004 ),
|
||||||
@ -1777,7 +1840,8 @@ typedef enum {
|
|||||||
* Self-relative security descriptor. Contains the owner and group SIDs as well
|
* Self-relative security descriptor. Contains the owner and group SIDs as well
|
||||||
* as the sacl and dacl ACLs inside the security descriptor itself.
|
* as the sacl and dacl ACLs inside the security descriptor itself.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 revision; /* Revision level of the security descriptor. */
|
u8 revision; /* Revision level of the security descriptor. */
|
||||||
u8 alignment;
|
u8 alignment;
|
||||||
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
|
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
|
||||||
@ -1809,7 +1873,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* On disk, a self-relative security descriptor is used.
|
* On disk, a self-relative security descriptor is used.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 revision; /* Revision level of the security descriptor. */
|
u8 revision; /* Revision level of the security descriptor. */
|
||||||
u8 alignment;
|
u8 alignment;
|
||||||
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
|
SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
|
||||||
@ -1835,7 +1900,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* Current constants for security descriptors.
|
* Current constants for security descriptors.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/* Current revision. */
|
/* Current revision. */
|
||||||
SECURITY_DESCRIPTOR_REVISION = 1,
|
SECURITY_DESCRIPTOR_REVISION = 1,
|
||||||
SECURITY_DESCRIPTOR_REVISION1 = 1,
|
SECURITY_DESCRIPTOR_REVISION1 = 1,
|
||||||
@ -1902,7 +1968,8 @@ typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR;
|
|||||||
* This header precedes each security descriptor in the $SDS data stream.
|
* This header precedes each security descriptor in the $SDS data stream.
|
||||||
* This is also the index entry data part of both the $SII and $SDH indexes.
|
* This is also the index entry data part of both the $SII and $SDH indexes.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 hash; /* Hash of the security descriptor. */
|
u32 hash; /* Hash of the security descriptor. */
|
||||||
u32 security_id; /* The security_id assigned to the descriptor. */
|
u32 security_id; /* The security_id assigned to the descriptor. */
|
||||||
u64 offset; /* Byte offset of this entry in the $SDS stream. */
|
u64 offset; /* Byte offset of this entry in the $SDS stream. */
|
||||||
@ -1912,7 +1979,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* struct SDH_INDEX_DATA -
|
* struct SDH_INDEX_DATA -
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 hash; /* Hash of the security descriptor. */
|
u32 hash; /* Hash of the security descriptor. */
|
||||||
u32 security_id; /* The security_id assigned to the descriptor. */
|
u32 security_id; /* The security_id assigned to the descriptor. */
|
||||||
u64 offset; /* Byte offset of this entry in the $SDS stream. */
|
u64 offset; /* Byte offset of this entry in the $SDS stream. */
|
||||||
@ -1939,7 +2007,8 @@ typedef SECURITY_DESCRIPTOR_HEADER SII_INDEX_DATA;
|
|||||||
* the first copy of the security descriptor will be at offset 0x51d0 in the
|
* the first copy of the security descriptor will be at offset 0x51d0 in the
|
||||||
* $SDS data stream and the second copy will be at offset 0x451d0.
|
* $SDS data stream and the second copy will be at offset 0x451d0.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like
|
/* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like
|
||||||
unnamed structs. */
|
unnamed structs. */
|
||||||
u32 hash; /* Hash of the security descriptor. */
|
u32 hash; /* Hash of the security descriptor. */
|
||||||
@ -1955,7 +2024,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* The collation type is COLLATION_NTOFS_ULONG.
|
* The collation type is COLLATION_NTOFS_ULONG.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 security_id; /* The security_id assigned to the descriptor. */
|
u32 security_id; /* The security_id assigned to the descriptor. */
|
||||||
} __attribute__( ( __packed__ ) ) SII_INDEX_KEY;
|
} __attribute__( ( __packed__ ) ) SII_INDEX_KEY;
|
||||||
|
|
||||||
@ -1965,7 +2035,8 @@ typedef struct {
|
|||||||
* The keys are sorted first by hash and then by security_id.
|
* The keys are sorted first by hash and then by security_id.
|
||||||
* The collation rule is COLLATION_NTOFS_SECURITY_HASH.
|
* The collation rule is COLLATION_NTOFS_SECURITY_HASH.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 hash; /* Hash of the security descriptor. */
|
u32 hash; /* Hash of the security descriptor. */
|
||||||
u32 security_id; /* The security_id assigned to the descriptor. */
|
u32 security_id; /* The security_id assigned to the descriptor. */
|
||||||
} __attribute__( ( __packed__ ) ) SDH_INDEX_KEY;
|
} __attribute__( ( __packed__ ) ) SDH_INDEX_KEY;
|
||||||
@ -1976,14 +2047,16 @@ typedef struct {
|
|||||||
* NOTE: Always resident.
|
* NOTE: Always resident.
|
||||||
* NOTE: Present only in FILE_Volume.
|
* NOTE: Present only in FILE_Volume.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
ntfschar name[0]; /* The name of the volume in Unicode. */
|
ntfschar name[0]; /* The name of the volume in Unicode. */
|
||||||
} __attribute__( ( __packed__ ) ) VOLUME_NAME;
|
} __attribute__( ( __packed__ ) ) VOLUME_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum VOLUME_FLAGS - Possible flags for the volume (16-bit).
|
* enum VOLUME_FLAGS - Possible flags for the volume (16-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
VOLUME_IS_DIRTY = const_cpu_to_le16( 0x0001 ),
|
VOLUME_IS_DIRTY = const_cpu_to_le16( 0x0001 ),
|
||||||
VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16( 0x0002 ),
|
VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16( 0x0002 ),
|
||||||
VOLUME_UPGRADE_ON_MOUNT = const_cpu_to_le16( 0x0004 ),
|
VOLUME_UPGRADE_ON_MOUNT = const_cpu_to_le16( 0x0004 ),
|
||||||
@ -2003,7 +2076,8 @@ typedef enum {
|
|||||||
* NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses
|
* NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses
|
||||||
* NTFS 1.2. I haven't personally seen other values yet.
|
* NTFS 1.2. I haven't personally seen other values yet.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u64 reserved; /* Not used (yet?). */
|
u64 reserved; /* Not used (yet?). */
|
||||||
u8 major_ver; /* Major version of the ntfs format. */
|
u8 major_ver; /* Major version of the ntfs format. */
|
||||||
u8 minor_ver; /* Minor version of the ntfs format. */
|
u8 minor_ver; /* Minor version of the ntfs format. */
|
||||||
@ -2017,14 +2091,16 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* Data contents of a file (i.e. the unnamed stream) or of a named stream.
|
* Data contents of a file (i.e. the unnamed stream) or of a named stream.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 data[0]; /* The file's data contents. */
|
u8 data[0]; /* The file's data contents. */
|
||||||
} __attribute__( ( __packed__ ) ) DATA_ATTR;
|
} __attribute__( ( __packed__ ) ) DATA_ATTR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum INDEX_HEADER_FLAGS - Index header flags (8-bit).
|
* enum INDEX_HEADER_FLAGS - Index header flags (8-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/* When index header is in an index root attribute: */
|
/* When index header is in an index root attribute: */
|
||||||
SMALL_INDEX = 0, /* The index is small enough to fit inside the
|
SMALL_INDEX = 0, /* The index is small enough to fit inside the
|
||||||
index root attribute and there is no index
|
index root attribute and there is no index
|
||||||
@ -2054,8 +2130,10 @@ typedef enum {
|
|||||||
* relative to the start of the index header structure and not relative to the
|
* relative to the start of the index header structure and not relative to the
|
||||||
* start of the index root or index allocation structures themselves.
|
* start of the index root or index allocation structures themselves.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* 0*/ u32 entries_offset; /* Byte offset from the INDEX_HEADER to first
|
{
|
||||||
|
/* 0*/
|
||||||
|
u32 entries_offset; /* Byte offset from the INDEX_HEADER to first
|
||||||
INDEX_ENTRY, aligned to 8-byte boundary. */
|
INDEX_ENTRY, aligned to 8-byte boundary. */
|
||||||
/* 4*/ u32 index_length; /* Data size in byte of the INDEX_ENTRY's,
|
/* 4*/ u32 index_length; /* Data size in byte of the INDEX_ENTRY's,
|
||||||
including the INDEX_HEADER, aligned to 8. */
|
including the INDEX_HEADER, aligned to 8. */
|
||||||
@ -2094,8 +2172,10 @@ typedef struct {
|
|||||||
* NOTE: The root directory (FILE_root) contains an entry for itself. Other
|
* NOTE: The root directory (FILE_root) contains an entry for itself. Other
|
||||||
* directories do not contain entries for themselves, though.
|
* directories do not contain entries for themselves, though.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* 0*/ ATTR_TYPES type; /* Type of the indexed attribute. Is
|
{
|
||||||
|
/* 0*/
|
||||||
|
ATTR_TYPES type; /* Type of the indexed attribute. Is
|
||||||
$FILE_NAME for directories, zero
|
$FILE_NAME for directories, zero
|
||||||
for view indexes. No other values
|
for view indexes. No other values
|
||||||
allowed. */
|
allowed. */
|
||||||
@ -2123,7 +2203,8 @@ typedef struct {
|
|||||||
* INDEX_BLOCK structure containing an index header, followed by a sequence of
|
* INDEX_BLOCK structure containing an index header, followed by a sequence of
|
||||||
* index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
|
* index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
NTFS_RECORD_TYPES magic;/* Magic is "INDX". */
|
NTFS_RECORD_TYPES magic;/* Magic is "INDX". */
|
||||||
u16 usa_ofs; /* See NTFS_RECORD definition. */
|
u16 usa_ofs; /* See NTFS_RECORD definition. */
|
||||||
@ -2158,7 +2239,8 @@ typedef INDEX_BLOCK INDEX_ALLOCATION;
|
|||||||
* COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the
|
* COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the
|
||||||
* primary key / is not a key at all. (AIA)
|
* primary key / is not a key at all. (AIA)
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 reparse_tag; /* Reparse point type (inc. flags). */
|
u32 reparse_tag; /* Reparse point type (inc. flags). */
|
||||||
MFT_REF file_id; /* Mft record of the file containing the
|
MFT_REF file_id; /* Mft record of the file containing the
|
||||||
reparse point attribute. */
|
reparse point attribute. */
|
||||||
@ -2167,7 +2249,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* enum QUOTA_FLAGS - Quota flags (32-bit).
|
* enum QUOTA_FLAGS - Quota flags (32-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
/* The user quota flags. Names explain meaning. */
|
/* The user quota flags. Names explain meaning. */
|
||||||
QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32( 0x00000001 ),
|
QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32( 0x00000001 ),
|
||||||
QUOTA_FLAG_LIMIT_REACHED = const_cpu_to_le32( 0x00000002 ),
|
QUOTA_FLAG_LIMIT_REACHED = const_cpu_to_le32( 0x00000002 ),
|
||||||
@ -2211,7 +2294,8 @@ typedef enum {
|
|||||||
*
|
*
|
||||||
* The $Q index entry data is the quota control entry and is defined below.
|
* The $Q index entry data is the quota control entry and is defined below.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 version; /* Currently equals 2. */
|
u32 version; /* Currently equals 2. */
|
||||||
QUOTA_FLAGS flags; /* Flags describing this quota entry. */
|
QUOTA_FLAGS flags; /* Flags describing this quota entry. */
|
||||||
u64 bytes_used; /* How many bytes of the quota are in use. */
|
u64 bytes_used; /* How many bytes of the quota are in use. */
|
||||||
@ -2233,7 +2317,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* struct QUOTA_O_INDEX_DATA -
|
* struct QUOTA_O_INDEX_DATA -
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 owner_id;
|
u32 owner_id;
|
||||||
u32 unknown; /* Always 32. Seems to be padding and it's not
|
u32 unknown; /* Always 32. Seems to be padding and it's not
|
||||||
counted in the INDEX_ENTRY's data_length.
|
counted in the INDEX_ENTRY's data_length.
|
||||||
@ -2243,7 +2328,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* enum PREDEFINED_OWNER_IDS - Predefined owner_id values (32-bit).
|
* enum PREDEFINED_OWNER_IDS - Predefined owner_id values (32-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
QUOTA_INVALID_ID = const_cpu_to_le32( 0x00000000 ),
|
QUOTA_INVALID_ID = const_cpu_to_le32( 0x00000000 ),
|
||||||
QUOTA_DEFAULTS_ID = const_cpu_to_le32( 0x00000001 ),
|
QUOTA_DEFAULTS_ID = const_cpu_to_le32( 0x00000001 ),
|
||||||
QUOTA_FIRST_USER_ID = const_cpu_to_le32( 0x00000100 ),
|
QUOTA_FIRST_USER_ID = const_cpu_to_le32( 0x00000100 ),
|
||||||
@ -2252,7 +2338,8 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* enum INDEX_ENTRY_FLAGS - Index entry flags (16-bit).
|
* enum INDEX_ENTRY_FLAGS - Index entry flags (16-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
INDEX_ENTRY_NODE = const_cpu_to_le16( 1 ), /* This entry contains a
|
INDEX_ENTRY_NODE = const_cpu_to_le16( 1 ), /* This entry contains a
|
||||||
sub-node, i.e. a reference to an index
|
sub-node, i.e. a reference to an index
|
||||||
block in form of a virtual cluster
|
block in form of a virtual cluster
|
||||||
@ -2271,10 +2358,14 @@ typedef enum {
|
|||||||
* !!!!! SEE DESCRIPTION OF THE FIELDS AT INDEX_ENTRY !!!!!
|
* !!!!! SEE DESCRIPTION OF THE FIELDS AT INDEX_ENTRY !!!!!
|
||||||
* ==========================================================
|
* ==========================================================
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* 0*/ union {
|
{
|
||||||
|
/* 0*/
|
||||||
|
union
|
||||||
|
{
|
||||||
MFT_REF indexed_file;
|
MFT_REF indexed_file;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
u16 data_offset;
|
u16 data_offset;
|
||||||
u16 data_length;
|
u16 data_length;
|
||||||
u32 reservedV;
|
u32 reservedV;
|
||||||
@ -2296,14 +2387,17 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* NOTE: Before NTFS 3.0 only filename attributes were indexed.
|
* NOTE: Before NTFS 3.0 only filename attributes were indexed.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */
|
/* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */
|
||||||
union { /* Only valid when INDEX_ENTRY_END is not set. */
|
union /* Only valid when INDEX_ENTRY_END is not set. */
|
||||||
|
{
|
||||||
MFT_REF indexed_file; /* The mft reference of the file
|
MFT_REF indexed_file; /* The mft reference of the file
|
||||||
described by this index
|
described by this index
|
||||||
entry. Used for directory
|
entry. Used for directory
|
||||||
indexes. */
|
indexes. */
|
||||||
struct { /* Used for views/indexes to find the entry's data. */
|
struct /* Used for views/indexes to find the entry's data. */
|
||||||
|
{
|
||||||
u16 data_offset; /* Data byte offset from this
|
u16 data_offset; /* Data byte offset from this
|
||||||
INDEX_ENTRY. Follows the
|
INDEX_ENTRY. Follows the
|
||||||
index key. */
|
index key. */
|
||||||
@ -2320,7 +2414,8 @@ typedef struct {
|
|||||||
/* 12*/ INDEX_ENTRY_FLAGS ie_flags; /* Bit field of INDEX_ENTRY_* flags. */
|
/* 12*/ INDEX_ENTRY_FLAGS ie_flags; /* Bit field of INDEX_ENTRY_* flags. */
|
||||||
/* 14*/ u16 reserved; /* Reserved/align to 8-byte boundary. */
|
/* 14*/ u16 reserved; /* Reserved/align to 8-byte boundary. */
|
||||||
/* End of INDEX_ENTRY_HEADER */
|
/* End of INDEX_ENTRY_HEADER */
|
||||||
/* 16*/ union { /* The key of the indexed attribute. NOTE: Only present
|
/* 16*/ union
|
||||||
|
{ /* The key of the indexed attribute. NOTE: Only present
|
||||||
if INDEX_ENTRY_END bit in flags is not set. NOTE: On
|
if INDEX_ENTRY_END bit in flags is not set. NOTE: On
|
||||||
NTFS versions before 3.0 the only valid key is the
|
NTFS versions before 3.0 the only valid key is the
|
||||||
FILE_NAME_ATTR. On NTFS 3.0+ the following
|
FILE_NAME_ATTR. On NTFS 3.0+ the following
|
||||||
@ -2364,7 +2459,8 @@ typedef struct {
|
|||||||
* the number of bits in the bitmap * index block size / cluster size is the
|
* the number of bits in the bitmap * index block size / cluster size is the
|
||||||
* number of clusters in the index allocation attribute.
|
* number of clusters in the index allocation attribute.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u8 bitmap[0]; /* Array of bits. */
|
u8 bitmap[0]; /* Array of bits. */
|
||||||
} __attribute__( ( __packed__ ) ) BITMAP_ATTR;
|
} __attribute__( ( __packed__ ) ) BITMAP_ATTR;
|
||||||
|
|
||||||
@ -2388,7 +2484,8 @@ typedef struct {
|
|||||||
* bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
|
* bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
|
||||||
* defined tags have to use zero here.
|
* defined tags have to use zero here.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32( 0x20000000 ),
|
IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32( 0x20000000 ),
|
||||||
IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32( 0x40000000 ),
|
IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32( 0x40000000 ),
|
||||||
IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32( 0x80000000 ),
|
IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32( 0x80000000 ),
|
||||||
@ -2416,7 +2513,8 @@ typedef enum {
|
|||||||
*
|
*
|
||||||
* NOTE: Can be resident or non-resident.
|
* NOTE: Can be resident or non-resident.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 reparse_tag; /* Reparse point type (inc. flags). */
|
u32 reparse_tag; /* Reparse point type (inc. flags). */
|
||||||
u16 reparse_data_length; /* Byte size of reparse data. */
|
u16 reparse_data_length; /* Byte size of reparse data. */
|
||||||
u16 reserved; /* Align to 8-byte boundary. */
|
u16 reserved; /* Align to 8-byte boundary. */
|
||||||
@ -2428,7 +2526,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* NOTE: Always resident.
|
* NOTE: Always resident.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u16 ea_length; /* Byte size of the packed extended
|
u16 ea_length; /* Byte size of the packed extended
|
||||||
attributes. */
|
attributes. */
|
||||||
u16 need_ea_count; /* The number of extended attributes which have
|
u16 need_ea_count; /* The number of extended attributes which have
|
||||||
@ -2443,7 +2542,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* enum EA_FLAGS - Extended attribute flags (8-bit).
|
* enum EA_FLAGS - Extended attribute flags (8-bit).
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NEED_EA = 0x80, /* Indicate that the file to which the EA
|
NEED_EA = 0x80, /* Indicate that the file to which the EA
|
||||||
belongs cannot be interpreted without
|
belongs cannot be interpreted without
|
||||||
understanding the associated extended
|
understanding the associated extended
|
||||||
@ -2459,7 +2559,8 @@ typedef enum {
|
|||||||
* FIXME: It appears weird that the EA name is not Unicode. Is it true?
|
* FIXME: It appears weird that the EA name is not Unicode. Is it true?
|
||||||
* FIXME: It seems that name is always uppercased. Is it true?
|
* FIXME: It seems that name is always uppercased. Is it true?
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 next_entry_offset; /* Offset to the next EA_ATTR. */
|
u32 next_entry_offset; /* Offset to the next EA_ATTR. */
|
||||||
EA_FLAGS flags; /* Flags describing the EA. */
|
EA_FLAGS flags; /* Flags describing the EA. */
|
||||||
u8 name_length; /* Length of the name of the extended
|
u8 name_length; /* Length of the name of the extended
|
||||||
@ -2476,7 +2577,8 @@ typedef struct {
|
|||||||
* Intended to support Native Structure Storage (NSS) - a feature removed from
|
* Intended to support Native Structure Storage (NSS) - a feature removed from
|
||||||
* NTFS 3.0 during beta testing.
|
* NTFS 3.0 during beta testing.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* Irrelevant as feature unused. */
|
/* Irrelevant as feature unused. */
|
||||||
} __attribute__( ( __packed__ ) ) PROPERTY_SET;
|
} __attribute__( ( __packed__ ) ) PROPERTY_SET;
|
||||||
|
|
||||||
@ -2491,7 +2593,8 @@ typedef struct {
|
|||||||
* Used by the Encrypting File System (EFS). All encrypted files have this
|
* Used by the Encrypting File System (EFS). All encrypted files have this
|
||||||
* attribute with the name $EFS. See below for the relevant structures.
|
* attribute with the name $EFS. See below for the relevant structures.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* Can be anything the creator chooses. */
|
/* Can be anything the creator chooses. */
|
||||||
} __attribute__( ( __packed__ ) ) LOGGED_UTILITY_STREAM;
|
} __attribute__( ( __packed__ ) ) LOGGED_UTILITY_STREAM;
|
||||||
|
|
||||||
@ -2527,8 +2630,10 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* The header of the Logged utility stream (0x100) attribute named "$EFS".
|
* The header of the Logged utility stream (0x100) attribute named "$EFS".
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* 0*/ u32 length; /* Length of EFS attribute in bytes. */
|
{
|
||||||
|
/* 0*/
|
||||||
|
u32 length; /* Length of EFS attribute in bytes. */
|
||||||
u32 state; /* Always 0? */
|
u32 state; /* Always 0? */
|
||||||
u32 version; /* Efs version. Always 2? */
|
u32 version; /* Efs version. Always 2? */
|
||||||
u32 crypto_api_version; /* Always 0? */
|
u32 crypto_api_version; /* Always 0? */
|
||||||
@ -2551,7 +2656,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* struct EFS_DF_ARRAY_HEADER -
|
* struct EFS_DF_ARRAY_HEADER -
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u32 df_count; /* Number of data decryption/recovery fields in
|
u32 df_count; /* Number of data decryption/recovery fields in
|
||||||
the array. */
|
the array. */
|
||||||
} __attribute__( ( __packed__ ) ) EFS_DF_ARRAY_HEADER;
|
} __attribute__( ( __packed__ ) ) EFS_DF_ARRAY_HEADER;
|
||||||
@ -2559,8 +2665,10 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* struct EFS_DF_HEADER -
|
* struct EFS_DF_HEADER -
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* 0*/ u32 df_length; /* Length of this data decryption/recovery
|
{
|
||||||
|
/* 0*/
|
||||||
|
u32 df_length; /* Length of this data decryption/recovery
|
||||||
field in bytes. */
|
field in bytes. */
|
||||||
u32 cred_header_offset; /* Offset in bytes to the credential header. */
|
u32 cred_header_offset; /* Offset in bytes to the credential header. */
|
||||||
u32 fek_size; /* Size in bytes of the encrypted file
|
u32 fek_size; /* Size in bytes of the encrypted file
|
||||||
@ -2573,8 +2681,10 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* struct EFS_DF_CREDENTIAL_HEADER -
|
* struct EFS_DF_CREDENTIAL_HEADER -
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* 0*/ u32 cred_length; /* Length of this credential in bytes. */
|
{
|
||||||
|
/* 0*/
|
||||||
|
u32 cred_length; /* Length of this credential in bytes. */
|
||||||
u32 sid_offset; /* Offset in bytes to the user's sid from start
|
u32 sid_offset; /* Offset in bytes to the user's sid from start
|
||||||
of this structure. Zero if no sid is
|
of this structure. Zero if no sid is
|
||||||
present. */
|
present. */
|
||||||
@ -2583,10 +2693,13 @@ typedef struct {
|
|||||||
2 = Unexpected type.
|
2 = Unexpected type.
|
||||||
3 = Certificate thumbprint.
|
3 = Certificate thumbprint.
|
||||||
other = Unknown type. */
|
other = Unknown type. */
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
/* CryptoAPI container. */
|
/* CryptoAPI container. */
|
||||||
struct {
|
struct
|
||||||
/* 12*/ u32 container_name_offset; /* Offset in bytes to
|
{
|
||||||
|
/* 12*/
|
||||||
|
u32 container_name_offset; /* Offset in bytes to
|
||||||
the name of the container from start of this
|
the name of the container from start of this
|
||||||
structure (may not be zero). */
|
structure (may not be zero). */
|
||||||
/* 16*/ u32 provider_name_offset; /* Offset in bytes to
|
/* 16*/ u32 provider_name_offset; /* Offset in bytes to
|
||||||
@ -2599,8 +2712,10 @@ typedef struct {
|
|||||||
public key blob. */
|
public key blob. */
|
||||||
} __attribute__( ( __packed__ ) );
|
} __attribute__( ( __packed__ ) );
|
||||||
/* Certificate thumbprint. */
|
/* Certificate thumbprint. */
|
||||||
struct {
|
struct
|
||||||
/* 12*/ u32 cert_thumbprint_header_size; /* Size in
|
{
|
||||||
|
/* 12*/
|
||||||
|
u32 cert_thumbprint_header_size; /* Size in
|
||||||
bytes of the header of the certificate
|
bytes of the header of the certificate
|
||||||
thumbprint. */
|
thumbprint. */
|
||||||
/* 16*/ u32 cert_thumbprint_header_offset; /* Offset in
|
/* 16*/ u32 cert_thumbprint_header_offset; /* Offset in
|
||||||
@ -2617,8 +2732,10 @@ typedef EFS_DF_CREDENTIAL_HEADER EFS_DF_CRED_HEADER;
|
|||||||
/**
|
/**
|
||||||
* struct EFS_DF_CERTIFICATE_THUMBPRINT_HEADER -
|
* struct EFS_DF_CERTIFICATE_THUMBPRINT_HEADER -
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* 0*/ u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */
|
{
|
||||||
|
/* 0*/
|
||||||
|
u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */
|
||||||
u32 thumbprint_size; /* Size of thumbprint in bytes. */
|
u32 thumbprint_size; /* Size of thumbprint in bytes. */
|
||||||
/* 8*/ u32 container_name_offset; /* Offset in bytes to the name of the
|
/* 8*/ u32 container_name_offset; /* Offset in bytes to the name of the
|
||||||
container from start of this
|
container from start of this
|
||||||
@ -2635,7 +2752,8 @@ typedef struct {
|
|||||||
|
|
||||||
typedef EFS_DF_CERTIFICATE_THUMBPRINT_HEADER EFS_DF_CERT_THUMBPRINT_HEADER;
|
typedef EFS_DF_CERTIFICATE_THUMBPRINT_HEADER EFS_DF_CERT_THUMBPRINT_HEADER;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
INTX_SYMBOLIC_LINK =
|
INTX_SYMBOLIC_LINK =
|
||||||
const_cpu_to_le64( 0x014B4E4C78746E49ULL ), /* "IntxLNK\1" */
|
const_cpu_to_le64( 0x014B4E4C78746E49ULL ), /* "IntxLNK\1" */
|
||||||
INTX_CHARACTER_DEVICE =
|
INTX_CHARACTER_DEVICE =
|
||||||
@ -2644,11 +2762,14 @@ typedef enum {
|
|||||||
const_cpu_to_le64( 0x004B4C4278746E49ULL ), /* "IntxBLK\0" */
|
const_cpu_to_le64( 0x004B4C4278746E49ULL ), /* "IntxBLK\0" */
|
||||||
} INTX_FILE_TYPES;
|
} INTX_FILE_TYPES;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
INTX_FILE_TYPES magic; /* Intx file magic. */
|
INTX_FILE_TYPES magic; /* Intx file magic. */
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
/* For character and block devices. */
|
/* For character and block devices. */
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
u64 major; /* Major device number. */
|
u64 major; /* Major device number. */
|
||||||
u64 minor; /* Minor device number. */
|
u64 minor; /* Minor device number. */
|
||||||
void *device_end[0]; /* Marker for offsetof(). */
|
void *device_end[0]; /* Marker for offsetof(). */
|
||||||
|
@ -55,7 +55,8 @@
|
|||||||
#define NTFS_LCNALLOC_BSIZE 4096
|
#define NTFS_LCNALLOC_BSIZE 4096
|
||||||
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
|
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
ZONE_MFT = 1,
|
ZONE_MFT = 1,
|
||||||
ZONE_DATA1 = 2,
|
ZONE_DATA1 = 2,
|
||||||
ZONE_DATA2 = 4
|
ZONE_DATA2 = 4
|
||||||
@ -94,19 +95,26 @@ static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
|
|||||||
|
|
||||||
static void update_full_status( ntfs_volume *vol, LCN lcn )
|
static void update_full_status( ntfs_volume *vol, LCN lcn )
|
||||||
{
|
{
|
||||||
if (lcn >= vol->mft_zone_end) {
|
if ( lcn >= vol->mft_zone_end )
|
||||||
if (vol->full_zones & ZONE_DATA1) {
|
{
|
||||||
|
if ( vol->full_zones & ZONE_DATA1 )
|
||||||
|
{
|
||||||
ntfs_cluster_update_zone_pos( vol, ZONE_DATA1, lcn );
|
ntfs_cluster_update_zone_pos( vol, ZONE_DATA1, lcn );
|
||||||
vol->full_zones &= ~ZONE_DATA1;
|
vol->full_zones &= ~ZONE_DATA1;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
if (lcn < vol->mft_zone_start) {
|
else if ( lcn < vol->mft_zone_start )
|
||||||
if (vol->full_zones & ZONE_DATA2) {
|
{
|
||||||
|
if ( vol->full_zones & ZONE_DATA2 )
|
||||||
|
{
|
||||||
ntfs_cluster_update_zone_pos( vol, ZONE_DATA2, lcn );
|
ntfs_cluster_update_zone_pos( vol, ZONE_DATA2, lcn );
|
||||||
vol->full_zones &= ~ZONE_DATA2;
|
vol->full_zones &= ~ZONE_DATA2;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (vol->full_zones & ZONE_MFT) {
|
else
|
||||||
|
{
|
||||||
|
if ( vol->full_zones & ZONE_MFT )
|
||||||
|
{
|
||||||
ntfs_cluster_update_zone_pos( vol, ZONE_MFT, lcn );
|
ntfs_cluster_update_zone_pos( vol, ZONE_MFT, lcn );
|
||||||
vol->full_zones &= ~ZONE_MFT;
|
vol->full_zones &= ~ZONE_MFT;
|
||||||
}
|
}
|
||||||
@ -122,38 +130,49 @@ static s64 max_empty_bit_range(unsigned char *buf, int size)
|
|||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace( "Entering\n" );
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < size) {
|
while ( i < size )
|
||||||
switch (*buf) {
|
{
|
||||||
|
switch ( *buf )
|
||||||
|
{
|
||||||
case 0 :
|
case 0 :
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
buf++;
|
buf++;
|
||||||
run += 8;
|
run += 8;
|
||||||
i++;
|
i++;
|
||||||
} while ((i < size) && !*buf);
|
}
|
||||||
|
while ( ( i < size ) && !*buf );
|
||||||
break;
|
break;
|
||||||
case 255 :
|
case 255 :
|
||||||
if (run > max_range) {
|
if ( run > max_range )
|
||||||
|
{
|
||||||
max_range = run;
|
max_range = run;
|
||||||
start_pos = ( s64 )i * 8 - run;
|
start_pos = ( s64 )i * 8 - run;
|
||||||
}
|
}
|
||||||
run = 0;
|
run = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
buf++;
|
buf++;
|
||||||
i++;
|
i++;
|
||||||
} while ((i < size) && (*buf == 255));
|
}
|
||||||
|
while ( ( i < size ) && ( *buf == 255 ) );
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
for (j = 0; j < 8; j++) {
|
for ( j = 0; j < 8; j++ )
|
||||||
|
{
|
||||||
|
|
||||||
int bit = *buf & ( 1 << j );
|
int bit = *buf & ( 1 << j );
|
||||||
|
|
||||||
if (bit) {
|
if ( bit )
|
||||||
if (run > max_range) {
|
{
|
||||||
|
if ( run > max_range )
|
||||||
|
{
|
||||||
max_range = run;
|
max_range = run;
|
||||||
start_pos = ( s64 )i * 8 + ( j - run );
|
start_pos = ( s64 )i * 8 + ( j - run );
|
||||||
}
|
}
|
||||||
run = 0;
|
run = 0;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
run++;
|
run++;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@ -181,7 +200,8 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
|
|||||||
*writeback = 0;
|
*writeback = 0;
|
||||||
|
|
||||||
written = ntfs_attr_pwrite( vol->lcnbmp_na, pos, size, b );
|
written = ntfs_attr_pwrite( vol->lcnbmp_na, pos, size, b );
|
||||||
if (written != size) {
|
if ( written != size )
|
||||||
|
{
|
||||||
if ( !written )
|
if ( !written )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Bitmap write error (%lld, %lld)",
|
ntfs_log_perror( "Bitmap write error (%lld, %lld)",
|
||||||
@ -253,7 +273,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA" );
|
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA" );
|
||||||
|
|
||||||
if ( !vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
|
if ( !vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
|
||||||
(s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
|
( s8 )zone < FIRST_ZONE || zone > LAST_ZONE )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: vcn: %lld, count: %lld, lcn: %lld",
|
ntfs_log_perror( "%s: vcn: %lld, count: %lld, lcn: %lld",
|
||||||
__FUNCTION__, ( long long )start_vcn,
|
__FUNCTION__, ( long long )start_vcn,
|
||||||
@ -262,9 +283,11 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return empty runlist if @count == 0 */
|
/* Return empty runlist if @count == 0 */
|
||||||
if (!count) {
|
if ( !count )
|
||||||
|
{
|
||||||
rl = ntfs_malloc( 0x1000 );
|
rl = ntfs_malloc( 0x1000 );
|
||||||
if (rl) {
|
if ( rl )
|
||||||
|
{
|
||||||
rl[0].vcn = start_vcn;
|
rl[0].vcn = start_vcn;
|
||||||
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
||||||
rl[0].length = 0;
|
rl[0].length = 0;
|
||||||
@ -282,7 +305,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
has_guess = 1;
|
has_guess = 1;
|
||||||
zone_start = start_lcn;
|
zone_start = start_lcn;
|
||||||
|
|
||||||
if (zone_start < 0) {
|
if ( zone_start < 0 )
|
||||||
|
{
|
||||||
if ( zone == DATA_ZONE )
|
if ( zone == DATA_ZONE )
|
||||||
zone_start = vol->data1_zone_pos;
|
zone_start = vol->data1_zone_pos;
|
||||||
else
|
else
|
||||||
@ -296,13 +320,18 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
zone_start == vol->mft_zone_end )
|
zone_start == vol->mft_zone_end )
|
||||||
pass = 2;
|
pass = 2;
|
||||||
|
|
||||||
if (zone_start < vol->mft_zone_start) {
|
if ( zone_start < vol->mft_zone_start )
|
||||||
|
{
|
||||||
zone_end = vol->mft_zone_start;
|
zone_end = vol->mft_zone_start;
|
||||||
search_zone = ZONE_DATA2;
|
search_zone = ZONE_DATA2;
|
||||||
} else if (zone_start < vol->mft_zone_end) {
|
}
|
||||||
|
else if ( zone_start < vol->mft_zone_end )
|
||||||
|
{
|
||||||
zone_end = vol->mft_zone_end;
|
zone_end = vol->mft_zone_end;
|
||||||
search_zone = ZONE_MFT;
|
search_zone = ZONE_MFT;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
zone_end = vol->nr_clusters;
|
zone_end = vol->nr_clusters;
|
||||||
search_zone = ZONE_DATA1;
|
search_zone = ZONE_DATA1;
|
||||||
}
|
}
|
||||||
@ -312,14 +341,16 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
/* Loop until all clusters are allocated. */
|
/* Loop until all clusters are allocated. */
|
||||||
clusters = count;
|
clusters = count;
|
||||||
rlpos = rlsize = 0;
|
rlpos = rlsize = 0;
|
||||||
while (1) {
|
while ( 1 )
|
||||||
|
{
|
||||||
/* check whether we have exhausted the current zone */
|
/* check whether we have exhausted the current zone */
|
||||||
if ( search_zone & vol->full_zones )
|
if ( search_zone & vol->full_zones )
|
||||||
goto zone_pass_done;
|
goto zone_pass_done;
|
||||||
last_read_pos = bmp_pos >> 3;
|
last_read_pos = bmp_pos >> 3;
|
||||||
br = ntfs_attr_pread( vol->lcnbmp_na, last_read_pos,
|
br = ntfs_attr_pread( vol->lcnbmp_na, last_read_pos,
|
||||||
NTFS_LCNALLOC_BSIZE, buf );
|
NTFS_LCNALLOC_BSIZE, buf );
|
||||||
if (br <= 0) {
|
if ( br <= 0 )
|
||||||
|
{
|
||||||
if ( !br )
|
if ( !br )
|
||||||
goto zone_pass_done;
|
goto zone_pass_done;
|
||||||
err = errno;
|
err = errno;
|
||||||
@ -335,15 +366,20 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
bmp_pos &= ~7;
|
bmp_pos &= ~7;
|
||||||
writeback = 0;
|
writeback = 0;
|
||||||
|
|
||||||
while (lcn < buf_size) {
|
while ( lcn < buf_size )
|
||||||
|
{
|
||||||
byte = buf + ( lcn >> 3 );
|
byte = buf + ( lcn >> 3 );
|
||||||
bit = 1 << ( lcn & 7 );
|
bit = 1 << ( lcn & 7 );
|
||||||
if (has_guess) {
|
if ( has_guess )
|
||||||
if (*byte & bit) {
|
{
|
||||||
|
if ( *byte & bit )
|
||||||
|
{
|
||||||
has_guess = 0;
|
has_guess = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
lcn = max_empty_bit_range( buf, br );
|
lcn = max_empty_bit_range( buf, br );
|
||||||
if ( lcn < 0 )
|
if ( lcn < 0 )
|
||||||
break;
|
break;
|
||||||
@ -354,10 +390,12 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
/* First free bit is at lcn + bmp_pos. */
|
/* First free bit is at lcn + bmp_pos. */
|
||||||
|
|
||||||
/* Reallocate memory if necessary. */
|
/* Reallocate memory if necessary. */
|
||||||
if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
|
if ( ( rlpos + 2 ) * ( int )sizeof( runlist ) >= rlsize )
|
||||||
|
{
|
||||||
rlsize += 4096;
|
rlsize += 4096;
|
||||||
trl = realloc( rl, rlsize );
|
trl = realloc( rl, rlsize );
|
||||||
if (!trl) {
|
if ( !trl )
|
||||||
|
{
|
||||||
err = ENOMEM;
|
err = ENOMEM;
|
||||||
ntfs_log_perror( "realloc() failed" );
|
ntfs_log_perror( "realloc() failed" );
|
||||||
goto wb_err_ret;
|
goto wb_err_ret;
|
||||||
@ -379,7 +417,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
* Coalesce with previous run if adjacent LCNs.
|
* Coalesce with previous run if adjacent LCNs.
|
||||||
* Otherwise, append a new run.
|
* Otherwise, append a new run.
|
||||||
*/
|
*/
|
||||||
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
|
if ( prev_lcn == lcn + bmp_pos - prev_run_len && rlpos )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Cluster coalesce: prev_lcn: "
|
ntfs_log_debug( "Cluster coalesce: prev_lcn: "
|
||||||
"%lld lcn: %lld bmp_pos: %lld "
|
"%lld lcn: %lld bmp_pos: %lld "
|
||||||
"prev_run_len: %lld\n",
|
"prev_run_len: %lld\n",
|
||||||
@ -387,11 +426,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
( long long )lcn, ( long long )bmp_pos,
|
( long long )lcn, ( long long )bmp_pos,
|
||||||
( long long )prev_run_len );
|
( long long )prev_run_len );
|
||||||
rl[rlpos - 1].length = ++prev_run_len;
|
rl[rlpos - 1].length = ++prev_run_len;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( rlpos )
|
if ( rlpos )
|
||||||
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
||||||
prev_run_len;
|
prev_run_len;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
rl[rlpos].vcn = start_vcn;
|
rl[rlpos].vcn = start_vcn;
|
||||||
ntfs_log_debug( "Start_vcn: %lld\n",
|
ntfs_log_debug( "Start_vcn: %lld\n",
|
||||||
( long long )start_vcn );
|
( long long )start_vcn );
|
||||||
@ -407,7 +449,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
( long long )rl[rlpos - 1].lcn,
|
( long long )rl[rlpos - 1].lcn,
|
||||||
( long long )rl[rlpos - 1].length );
|
( long long )rl[rlpos - 1].length );
|
||||||
/* Done? */
|
/* Done? */
|
||||||
if (!--clusters) {
|
if ( !--clusters )
|
||||||
|
{
|
||||||
if ( used_zone_pos )
|
if ( used_zone_pos )
|
||||||
ntfs_cluster_update_zone_pos( vol,
|
ntfs_cluster_update_zone_pos( vol,
|
||||||
search_zone, lcn + bmp_pos + 1 +
|
search_zone, lcn + bmp_pos + 1 +
|
||||||
@ -418,12 +461,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
lcn++;
|
lcn++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_ret;
|
goto err_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!used_zone_pos) {
|
if ( !used_zone_pos )
|
||||||
|
{
|
||||||
|
|
||||||
used_zone_pos = 1;
|
used_zone_pos = 1;
|
||||||
|
|
||||||
@ -438,7 +483,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
zone_start == vol->mft_zone_end )
|
zone_start == vol->mft_zone_end )
|
||||||
pass = 2;
|
pass = 2;
|
||||||
bmp_pos = zone_start;
|
bmp_pos = zone_start;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
bmp_pos += buf_size;
|
bmp_pos += buf_size;
|
||||||
|
|
||||||
if ( bmp_pos < zone_end )
|
if ( bmp_pos < zone_end )
|
||||||
@ -446,7 +492,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
|
|
||||||
zone_pass_done:
|
zone_pass_done:
|
||||||
ntfs_log_trace( "Finished current zone pass(%i).\n", pass );
|
ntfs_log_trace( "Finished current zone pass(%i).\n", pass );
|
||||||
if (pass == 1) {
|
if ( pass == 1 )
|
||||||
|
{
|
||||||
pass = 2;
|
pass = 2;
|
||||||
zone_end = zone_start;
|
zone_end = zone_start;
|
||||||
|
|
||||||
@ -469,10 +516,12 @@ zone_pass_done:
|
|||||||
done_zones_check:
|
done_zones_check:
|
||||||
done_zones |= search_zone;
|
done_zones |= search_zone;
|
||||||
vol->full_zones |= search_zone;
|
vol->full_zones |= search_zone;
|
||||||
if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2)) {
|
if ( done_zones < ( ZONE_MFT + ZONE_DATA1 + ZONE_DATA2 ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Switching zone.\n" );
|
ntfs_log_trace( "Switching zone.\n" );
|
||||||
pass = 1;
|
pass = 1;
|
||||||
if (rlpos) {
|
if ( rlpos )
|
||||||
|
{
|
||||||
LCN tc = rl[rlpos - 1].lcn +
|
LCN tc = rl[rlpos - 1].lcn +
|
||||||
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
||||||
|
|
||||||
@ -481,7 +530,8 @@ done_zones_check:
|
|||||||
search_zone, tc );
|
search_zone, tc );
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (search_zone) {
|
switch ( search_zone )
|
||||||
|
{
|
||||||
case ZONE_MFT:
|
case ZONE_MFT:
|
||||||
ntfs_log_trace( "Zone switch: mft -> data1\n" );
|
ntfs_log_trace( "Zone switch: mft -> data1\n" );
|
||||||
switch_to_data1_zone: search_zone = ZONE_DATA1;
|
switch_to_data1_zone: search_zone = ZONE_DATA1;
|
||||||
@ -499,7 +549,8 @@ switch_to_data1_zone: search_zone = ZONE_DATA1;
|
|||||||
pass = 2;
|
pass = 2;
|
||||||
break;
|
break;
|
||||||
case ZONE_DATA2:
|
case ZONE_DATA2:
|
||||||
if (!(done_zones & ZONE_DATA1)) {
|
if ( !( done_zones & ZONE_DATA1 ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "data2 -> data1\n" );
|
ntfs_log_trace( "data2 -> data1\n" );
|
||||||
goto switch_to_data1_zone;
|
goto switch_to_data1_zone;
|
||||||
}
|
}
|
||||||
@ -514,7 +565,8 @@ switch_to_data1_zone: search_zone = ZONE_DATA1;
|
|||||||
|
|
||||||
bmp_pos = zone_start;
|
bmp_pos = zone_start;
|
||||||
|
|
||||||
if (zone_start == zone_end) {
|
if ( zone_start == zone_end )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Empty zone, skipped.\n" );
|
ntfs_log_trace( "Empty zone, skipped.\n" );
|
||||||
goto done_zones_check;
|
goto done_zones_check;
|
||||||
}
|
}
|
||||||
@ -532,13 +584,15 @@ done_ret:
|
|||||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||||
rl[rlpos].length = 0;
|
rl[rlpos].length = 0;
|
||||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_ret;
|
goto err_ret;
|
||||||
}
|
}
|
||||||
done_err_ret:
|
done_err_ret:
|
||||||
free( buf );
|
free( buf );
|
||||||
if (err) {
|
if ( err )
|
||||||
|
{
|
||||||
errno = err;
|
errno = err;
|
||||||
ntfs_log_perror( "Failed to allocate clusters" );
|
ntfs_log_perror( "Failed to allocate clusters" );
|
||||||
rl = NULL;
|
rl = NULL;
|
||||||
@ -553,7 +607,8 @@ wb_err_ret:
|
|||||||
err = errno;
|
err = errno;
|
||||||
err_ret:
|
err_ret:
|
||||||
ntfs_log_trace( "At err_ret.\n" );
|
ntfs_log_trace( "At err_ret.\n" );
|
||||||
if (rl) {
|
if ( rl )
|
||||||
|
{
|
||||||
/* Add runlist terminator element. */
|
/* Add runlist terminator element. */
|
||||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||||
@ -580,15 +635,18 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace( "Entering.\n" );
|
||||||
|
|
||||||
for (; rl->length; rl++) {
|
for ( ; rl->length; rl++ )
|
||||||
|
{
|
||||||
|
|
||||||
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
|
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||||
( long long )rl->lcn, ( long long )rl->length );
|
( long long )rl->lcn, ( long long )rl->length );
|
||||||
|
|
||||||
if (rl->lcn >= 0) {
|
if ( rl->lcn >= 0 )
|
||||||
|
{
|
||||||
update_full_status( vol, rl->lcn );
|
update_full_status( vol, rl->lcn );
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
||||||
rl->length)) {
|
rl->length ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Cluster deallocation failed "
|
ntfs_log_perror( "Cluster deallocation failed "
|
||||||
"(%lld, %lld)",
|
"(%lld, %lld)",
|
||||||
( long long )rl->lcn,
|
( long long )rl->lcn,
|
||||||
@ -623,10 +681,12 @@ int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count)
|
|||||||
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
|
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||||
( long long )lcn, ( long long )count );
|
( long long )lcn, ( long long )count );
|
||||||
|
|
||||||
if (lcn >= 0) {
|
if ( lcn >= 0 )
|
||||||
|
{
|
||||||
update_full_status( vol, lcn );
|
update_full_status( vol, lcn );
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, lcn,
|
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, lcn,
|
||||||
count)) {
|
count ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Cluster deallocation failed "
|
ntfs_log_perror( "Cluster deallocation failed "
|
||||||
"(%lld, %lld)",
|
"(%lld, %lld)",
|
||||||
( long long )lcn,
|
( long long )lcn,
|
||||||
@ -668,7 +728,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
|||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if ( !vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
|
if ( !vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
|
||||||
(count < 0 && count != -1)) {
|
( count < 0 && count != -1 ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Invalid arguments!\n" );
|
ntfs_log_trace( "Invalid arguments!\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -679,13 +740,15 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
|||||||
na->type, ( long long )count, ( long long )start_vcn );
|
na->type, ( long long )count, ( long long )start_vcn );
|
||||||
|
|
||||||
rl = ntfs_attr_find_vcn( na, start_vcn );
|
rl = ntfs_attr_find_vcn( na, start_vcn );
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
if ( errno == ENOENT )
|
if ( errno == ENOENT )
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
if ( rl->lcn < 0 && rl->lcn != LCN_HOLE )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: Unexpected lcn (%lld)", __FUNCTION__,
|
ntfs_log_perror( "%s: Unexpected lcn (%lld)", __FUNCTION__,
|
||||||
( long long )rl->lcn );
|
( long long )rl->lcn );
|
||||||
@ -700,7 +763,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
|||||||
if ( count >= 0 && to_free > count )
|
if ( count >= 0 && to_free > count )
|
||||||
to_free = count;
|
to_free = count;
|
||||||
|
|
||||||
if (rl->lcn != LCN_HOLE) {
|
if ( rl->lcn != LCN_HOLE )
|
||||||
|
{
|
||||||
/* Do the actual freeing of the clusters in this run. */
|
/* Do the actual freeing of the clusters in this run. */
|
||||||
update_full_status( vol, rl->lcn + delta );
|
update_full_status( vol, rl->lcn + delta );
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn + delta,
|
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn + delta,
|
||||||
@ -718,10 +782,12 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
|||||||
* Loop over the remaining runs, using @count as a capping value, and
|
* Loop over the remaining runs, using @count as a capping value, and
|
||||||
* free them.
|
* free them.
|
||||||
*/
|
*/
|
||||||
for (; rl->length && count != 0; ++rl) {
|
for ( ; rl->length && count != 0; ++rl )
|
||||||
|
{
|
||||||
// FIXME: Need to try ntfs_attr_map_runlist() for attribute
|
// FIXME: Need to try ntfs_attr_map_runlist() for attribute
|
||||||
// list support! (AIA)
|
// list support! (AIA)
|
||||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
if ( rl->lcn < 0 && rl->lcn != LCN_HOLE )
|
||||||
|
{
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: Invalid lcn (%lli)",
|
ntfs_log_perror( "%s: Invalid lcn (%lli)",
|
||||||
@ -734,10 +800,12 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
|||||||
if ( count >= 0 && to_free > count )
|
if ( count >= 0 && to_free > count )
|
||||||
to_free = count;
|
to_free = count;
|
||||||
|
|
||||||
if (rl->lcn != LCN_HOLE) {
|
if ( rl->lcn != LCN_HOLE )
|
||||||
|
{
|
||||||
update_full_status( vol, rl->lcn );
|
update_full_status( vol, rl->lcn );
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
||||||
to_free)) {
|
to_free ) )
|
||||||
|
{
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
ntfs_log_perror( "%s: Clearing bitmap run failed",
|
ntfs_log_perror( "%s: Clearing bitmap run failed",
|
||||||
__FUNCTION__ );
|
__FUNCTION__ );
|
||||||
@ -750,7 +818,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
|||||||
count -= to_free;
|
count -= to_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count != -1 && count != 0) {
|
if ( count != -1 && count != 0 )
|
||||||
|
{
|
||||||
// FIXME: Eeek! BUG()
|
// FIXME: Eeek! BUG()
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: count still not zero (%lld)", __FUNCTION__,
|
ntfs_log_perror( "%s: count still not zero (%lld)", __FUNCTION__,
|
||||||
|
@ -31,7 +31,8 @@
|
|||||||
/**
|
/**
|
||||||
* enum NTFS_CLUSTER_ALLOCATION_ZONES -
|
* enum NTFS_CLUSTER_ALLOCATION_ZONES -
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
FIRST_ZONE = 0, /* For sanity checking. */
|
FIRST_ZONE = 0, /* For sanity checking. */
|
||||||
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
||||||
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
||||||
|
@ -71,7 +71,8 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
|||||||
logfile_log_page_size < NTFS_BLOCK_SIZE ||
|
logfile_log_page_size < NTFS_BLOCK_SIZE ||
|
||||||
logfile_system_page_size &
|
logfile_system_page_size &
|
||||||
( logfile_system_page_size - 1 ) ||
|
( logfile_system_page_size - 1 ) ||
|
||||||
logfile_log_page_size & (logfile_log_page_size - 1)) {
|
logfile_log_page_size & ( logfile_log_page_size - 1 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile uses unsupported page size.\n" );
|
ntfs_log_error( "$LogFile uses unsupported page size.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -79,14 +80,16 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
|||||||
* We must be either at !pos (1st restart page) or at pos = system page
|
* We must be either at !pos (1st restart page) or at pos = system page
|
||||||
* size (2nd restart page).
|
* size (2nd restart page).
|
||||||
*/
|
*/
|
||||||
if (pos && pos != logfile_system_page_size) {
|
if ( pos && pos != logfile_system_page_size )
|
||||||
|
{
|
||||||
ntfs_log_error( "Found restart area in incorrect "
|
ntfs_log_error( "Found restart area in incorrect "
|
||||||
"position in $LogFile.\n" );
|
"position in $LogFile.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* We only know how to handle version 1.1. */
|
/* We only know how to handle version 1.1. */
|
||||||
if ( sle16_to_cpu( rp->major_ver ) != 1 ||
|
if ( sle16_to_cpu( rp->major_ver ) != 1 ||
|
||||||
sle16_to_cpu(rp->minor_ver) != 1) {
|
sle16_to_cpu( rp->minor_ver ) != 1 )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile version %i.%i is not "
|
ntfs_log_error( "$LogFile version %i.%i is not "
|
||||||
"supported. (This driver supports version "
|
"supported. (This driver supports version "
|
||||||
"1.1 only.)\n", ( int )sle16_to_cpu( rp->major_ver ),
|
"1.1 only.)\n", ( int )sle16_to_cpu( rp->major_ver ),
|
||||||
@ -97,13 +100,15 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
|||||||
* If chkdsk has been run the restart page may not be protected by an
|
* If chkdsk has been run the restart page may not be protected by an
|
||||||
* update sequence array.
|
* update sequence array.
|
||||||
*/
|
*/
|
||||||
if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
|
if ( ntfs_is_chkd_record( rp->magic ) && !le16_to_cpu( rp->usa_count ) )
|
||||||
|
{
|
||||||
have_usa = FALSE;
|
have_usa = FALSE;
|
||||||
goto skip_usa_checks;
|
goto skip_usa_checks;
|
||||||
}
|
}
|
||||||
/* Verify the size of the update sequence array. */
|
/* Verify the size of the update sequence array. */
|
||||||
usa_count = 1 + ( logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS );
|
usa_count = 1 + ( logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS );
|
||||||
if (usa_count != le16_to_cpu(rp->usa_count)) {
|
if ( usa_count != le16_to_cpu( rp->usa_count ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart page specifies "
|
ntfs_log_error( "$LogFile restart page specifies "
|
||||||
"inconsistent update sequence array count.\n" );
|
"inconsistent update sequence array count.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -112,7 +117,8 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
|||||||
usa_ofs = le16_to_cpu( rp->usa_ofs );
|
usa_ofs = le16_to_cpu( rp->usa_ofs );
|
||||||
usa_end = usa_ofs + usa_count * sizeof( u16 );
|
usa_end = usa_ofs + usa_count * sizeof( u16 );
|
||||||
if ( usa_ofs < sizeof( RESTART_PAGE_HEADER ) ||
|
if ( usa_ofs < sizeof( RESTART_PAGE_HEADER ) ||
|
||||||
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
|
usa_end > NTFS_BLOCK_SIZE - sizeof( u16 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart page specifies "
|
ntfs_log_error( "$LogFile restart page specifies "
|
||||||
"inconsistent update sequence array offset.\n" );
|
"inconsistent update sequence array offset.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -127,7 +133,8 @@ skip_usa_checks:
|
|||||||
ra_ofs = le16_to_cpu( rp->restart_area_offset );
|
ra_ofs = le16_to_cpu( rp->restart_area_offset );
|
||||||
if ( ra_ofs & 7 || ( have_usa ? ra_ofs < usa_end :
|
if ( ra_ofs & 7 || ( have_usa ? ra_ofs < usa_end :
|
||||||
ra_ofs < sizeof( RESTART_PAGE_HEADER ) ) ||
|
ra_ofs < sizeof( RESTART_PAGE_HEADER ) ) ||
|
||||||
ra_ofs > logfile_system_page_size) {
|
ra_ofs > logfile_system_page_size )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart page specifies "
|
ntfs_log_error( "$LogFile restart page specifies "
|
||||||
"inconsistent restart area offset.\n" );
|
"inconsistent restart area offset.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -136,7 +143,8 @@ skip_usa_checks:
|
|||||||
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
|
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
|
||||||
* set.
|
* set.
|
||||||
*/
|
*/
|
||||||
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
|
if ( !ntfs_is_chkd_record( rp->magic ) && sle64_to_cpu( rp->chkdsk_lsn ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart page is not modified "
|
ntfs_log_error( "$LogFile restart page is not modified "
|
||||||
"by chkdsk but a chkdsk LSN is specified.\n" );
|
"by chkdsk but a chkdsk LSN is specified.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -174,7 +182,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
|||||||
* safe to access ra->client_array_offset.
|
* safe to access ra->client_array_offset.
|
||||||
*/
|
*/
|
||||||
if ( ra_ofs + offsetof( RESTART_AREA, file_size ) >
|
if ( ra_ofs + offsetof( RESTART_AREA, file_size ) >
|
||||||
NTFS_BLOCK_SIZE - sizeof(u16)) {
|
NTFS_BLOCK_SIZE - sizeof( u16 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
ntfs_log_error( "$LogFile restart area specifies "
|
||||||
"inconsistent file offset.\n" );
|
"inconsistent file offset.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -189,7 +198,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
|||||||
ca_ofs = le16_to_cpu( ra->client_array_offset );
|
ca_ofs = le16_to_cpu( ra->client_array_offset );
|
||||||
if ( ( ( ca_ofs + 7 ) & ~7 ) != ca_ofs ||
|
if ( ( ( ca_ofs + 7 ) & ~7 ) != ca_ofs ||
|
||||||
ra_ofs + ca_ofs > ( u16 )( NTFS_BLOCK_SIZE -
|
ra_ofs + ca_ofs > ( u16 )( NTFS_BLOCK_SIZE -
|
||||||
sizeof(u16))) {
|
sizeof( u16 ) ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
ntfs_log_error( "$LogFile restart area specifies "
|
||||||
"inconsistent client array offset.\n" );
|
"inconsistent client array offset.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -204,7 +214,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
|||||||
if ( ( u32 )( ra_ofs + ra_len ) > le32_to_cpu( rp->system_page_size ) ||
|
if ( ( u32 )( ra_ofs + ra_len ) > le32_to_cpu( rp->system_page_size ) ||
|
||||||
( u32 )( ra_ofs + le16_to_cpu( ra->restart_area_length ) ) >
|
( u32 )( ra_ofs + le16_to_cpu( ra->restart_area_length ) ) >
|
||||||
le32_to_cpu( rp->system_page_size ) ||
|
le32_to_cpu( rp->system_page_size ) ||
|
||||||
ra_len > le16_to_cpu(ra->restart_area_length)) {
|
ra_len > le16_to_cpu( ra->restart_area_length ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart area is out of bounds "
|
ntfs_log_error( "$LogFile restart area is out of bounds "
|
||||||
"of the system page size specified by the "
|
"of the system page size specified by the "
|
||||||
"restart page header and/or the specified "
|
"restart page header and/or the specified "
|
||||||
@ -221,7 +232,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
|||||||
le16_to_cpu( ra->log_clients ) ) ||
|
le16_to_cpu( ra->log_clients ) ) ||
|
||||||
( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||||
le16_to_cpu( ra->client_in_use_list ) >=
|
le16_to_cpu( ra->client_in_use_list ) >=
|
||||||
le16_to_cpu(ra->log_clients))) {
|
le16_to_cpu( ra->log_clients ) ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
ntfs_log_error( "$LogFile restart area specifies "
|
||||||
"overflowing client free and/or in use lists.\n" );
|
"overflowing client free and/or in use lists.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -232,25 +244,29 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
|||||||
*/
|
*/
|
||||||
file_size = ( u64 )sle64_to_cpu( ra->file_size );
|
file_size = ( u64 )sle64_to_cpu( ra->file_size );
|
||||||
fs_bits = 0;
|
fs_bits = 0;
|
||||||
while (file_size) {
|
while ( file_size )
|
||||||
|
{
|
||||||
file_size >>= 1;
|
file_size >>= 1;
|
||||||
fs_bits++;
|
fs_bits++;
|
||||||
}
|
}
|
||||||
if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) {
|
if ( le32_to_cpu( ra->seq_number_bits ) != ( u32 )( 67 - fs_bits ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
ntfs_log_error( "$LogFile restart area specifies "
|
||||||
"inconsistent sequence number bits.\n" );
|
"inconsistent sequence number bits.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* The log record header length must be a multiple of 8. */
|
/* The log record header length must be a multiple of 8. */
|
||||||
if ( ( ( le16_to_cpu( ra->log_record_header_length ) + 7 ) & ~7 ) !=
|
if ( ( ( le16_to_cpu( ra->log_record_header_length ) + 7 ) & ~7 ) !=
|
||||||
le16_to_cpu(ra->log_record_header_length)) {
|
le16_to_cpu( ra->log_record_header_length ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
ntfs_log_error( "$LogFile restart area specifies "
|
||||||
"inconsistent log record header length.\n" );
|
"inconsistent log record header length.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* Ditto for the log page data offset. */
|
/* Ditto for the log page data offset. */
|
||||||
if ( ( ( le16_to_cpu( ra->log_page_data_offset ) + 7 ) & ~7 ) !=
|
if ( ( ( le16_to_cpu( ra->log_page_data_offset ) + 7 ) & ~7 ) !=
|
||||||
le16_to_cpu(ra->log_page_data_offset)) {
|
le16_to_cpu( ra->log_page_data_offset ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
ntfs_log_error( "$LogFile restart area specifies "
|
||||||
"inconsistent log page data offset.\n" );
|
"inconsistent log page data offset.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -297,20 +313,23 @@ static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
|
|||||||
in_free_list = TRUE;
|
in_free_list = TRUE;
|
||||||
check_list:
|
check_list:
|
||||||
for ( idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
|
for ( idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
|
||||||
idx = le16_to_cpu(cr->next_client)) {
|
idx = le16_to_cpu( cr->next_client ) )
|
||||||
|
{
|
||||||
if ( !nr_clients || idx >= le16_to_cpu( ra->log_clients ) )
|
if ( !nr_clients || idx >= le16_to_cpu( ra->log_clients ) )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
/* Set @cr to the current log client record. */
|
/* Set @cr to the current log client record. */
|
||||||
cr = ca + idx;
|
cr = ca + idx;
|
||||||
/* The first log client record must not have a prev_client. */
|
/* The first log client record must not have a prev_client. */
|
||||||
if (idx_is_first) {
|
if ( idx_is_first )
|
||||||
|
{
|
||||||
if ( cr->prev_client != LOGFILE_NO_CLIENT )
|
if ( cr->prev_client != LOGFILE_NO_CLIENT )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
idx_is_first = FALSE;
|
idx_is_first = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Switch to and check the in use list if we just did the free list. */
|
/* Switch to and check the in use list if we just did the free list. */
|
||||||
if (in_free_list) {
|
if ( in_free_list )
|
||||||
|
{
|
||||||
in_free_list = FALSE;
|
in_free_list = FALSE;
|
||||||
idx = le16_to_cpu( ra->client_in_use_list );
|
idx = le16_to_cpu( ra->client_in_use_list );
|
||||||
goto check_list;
|
goto check_list;
|
||||||
@ -359,12 +378,14 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace( "Entering.\n" );
|
||||||
/* Check the restart page header for consistency. */
|
/* Check the restart page header for consistency. */
|
||||||
if (!ntfs_check_restart_page_header(rp, pos)) {
|
if ( !ntfs_check_restart_page_header( rp, pos ) )
|
||||||
|
{
|
||||||
/* Error output already done inside the function. */
|
/* Error output already done inside the function. */
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
/* Check the restart area for consistency. */
|
/* Check the restart area for consistency. */
|
||||||
if (!ntfs_check_restart_area(rp)) {
|
if ( !ntfs_check_restart_area( rp ) )
|
||||||
|
{
|
||||||
/* Error output already done inside the function. */
|
/* Error output already done inside the function. */
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -385,7 +406,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
|||||||
memcpy( trp, rp, le32_to_cpu( rp->system_page_size ) );
|
memcpy( trp, rp, le32_to_cpu( rp->system_page_size ) );
|
||||||
else if ( ntfs_attr_pread( log_na, pos,
|
else if ( ntfs_attr_pread( log_na, pos,
|
||||||
le32_to_cpu( rp->system_page_size ), trp ) !=
|
le32_to_cpu( rp->system_page_size ), trp ) !=
|
||||||
le32_to_cpu(rp->system_page_size)) {
|
le32_to_cpu( rp->system_page_size ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_error( "Failed to read whole restart page into the "
|
ntfs_log_error( "Failed to read whole restart page into the "
|
||||||
"buffer.\n" );
|
"buffer.\n" );
|
||||||
@ -399,7 +421,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
|||||||
*/
|
*/
|
||||||
if ( ( !ntfs_is_chkd_record( trp->magic ) || le16_to_cpu( trp->usa_count ) )
|
if ( ( !ntfs_is_chkd_record( trp->magic ) || le16_to_cpu( trp->usa_count ) )
|
||||||
&& ntfs_mst_post_read_fixup( ( NTFS_RECORD* )trp,
|
&& ntfs_mst_post_read_fixup( ( NTFS_RECORD* )trp,
|
||||||
le32_to_cpu(rp->system_page_size))) {
|
le32_to_cpu( rp->system_page_size ) ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* A multi sector tranfer error was detected. We only need to
|
* A multi sector tranfer error was detected. We only need to
|
||||||
* abort if the restart page contents exceed the multi sector
|
* abort if the restart page contents exceed the multi sector
|
||||||
@ -407,7 +430,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
|||||||
*/
|
*/
|
||||||
if ( le16_to_cpu( rp->restart_area_offset ) +
|
if ( le16_to_cpu( rp->restart_area_offset ) +
|
||||||
le16_to_cpu( ra->restart_area_length ) >
|
le16_to_cpu( ra->restart_area_length ) >
|
||||||
NTFS_BLOCK_SIZE - (int)sizeof(u16)) {
|
NTFS_BLOCK_SIZE - ( int )sizeof( u16 ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Multi sector transfer error "
|
ntfs_log_error( "Multi sector transfer error "
|
||||||
"detected in $LogFile restart page.\n" );
|
"detected in $LogFile restart page.\n" );
|
||||||
err = EINVAL;
|
err = EINVAL;
|
||||||
@ -421,13 +445,16 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
|||||||
*/
|
*/
|
||||||
err = 0;
|
err = 0;
|
||||||
if ( ntfs_is_rstr_record( rp->magic ) &&
|
if ( ntfs_is_rstr_record( rp->magic ) &&
|
||||||
ra->client_in_use_list != LOGFILE_NO_CLIENT) {
|
ra->client_in_use_list != LOGFILE_NO_CLIENT )
|
||||||
if (!ntfs_check_log_client_array(trp)) {
|
{
|
||||||
|
if ( !ntfs_check_log_client_array( trp ) )
|
||||||
|
{
|
||||||
err = EINVAL;
|
err = EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lsn) {
|
if ( lsn )
|
||||||
|
{
|
||||||
if ( ntfs_is_rstr_record( rp->magic ) )
|
if ( ntfs_is_rstr_record( rp->magic ) )
|
||||||
*lsn = sle64_to_cpu( ra->current_lsn );
|
*lsn = sle64_to_cpu( ra->current_lsn );
|
||||||
else /* if (ntfs_is_chkd_record(rp->magic)) */
|
else /* if (ntfs_is_chkd_record(rp->magic)) */
|
||||||
@ -436,7 +463,8 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
|||||||
ntfs_log_trace( "Done.\n" );
|
ntfs_log_trace( "Done.\n" );
|
||||||
if ( wrp )
|
if ( wrp )
|
||||||
*wrp = trp;
|
*wrp = trp;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
err_out:
|
err_out:
|
||||||
free( trp );
|
free( trp );
|
||||||
}
|
}
|
||||||
@ -494,7 +522,8 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
|||||||
* pages and the minimum number of log record pages.
|
* pages and the minimum number of log record pages.
|
||||||
*/
|
*/
|
||||||
if ( size < log_page_size * 2 || ( size - log_page_size * 2 ) >>
|
if ( size < log_page_size * 2 || ( size - log_page_size * 2 ) >>
|
||||||
log_page_bits < MinLogRecordPages) {
|
log_page_bits < MinLogRecordPages )
|
||||||
|
{
|
||||||
ntfs_log_error( "$LogFile is too small.\n" );
|
ntfs_log_error( "$LogFile is too small.\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -510,12 +539,14 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
|||||||
* contain empty and uninitialized records, the log file can be assumed
|
* contain empty and uninitialized records, the log file can be assumed
|
||||||
* to be empty.
|
* to be empty.
|
||||||
*/
|
*/
|
||||||
for (pos = 0; pos < size; pos <<= 1) {
|
for ( pos = 0; pos < size; pos <<= 1 )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Read first NTFS_BLOCK_SIZE bytes of potential restart page.
|
* Read first NTFS_BLOCK_SIZE bytes of potential restart page.
|
||||||
*/
|
*/
|
||||||
if ( ntfs_attr_pread( log_na, pos, NTFS_BLOCK_SIZE, kaddr ) !=
|
if ( ntfs_attr_pread( log_na, pos, NTFS_BLOCK_SIZE, kaddr ) !=
|
||||||
NTFS_BLOCK_SIZE) {
|
NTFS_BLOCK_SIZE )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to read first NTFS_BLOCK_SIZE "
|
ntfs_log_error( "Failed to read first NTFS_BLOCK_SIZE "
|
||||||
"bytes of potential restart page.\n" );
|
"bytes of potential restart page.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -538,7 +569,8 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
|||||||
break;
|
break;
|
||||||
/* If not a (modified by chkdsk) restart page, continue. */
|
/* If not a (modified by chkdsk) restart page, continue. */
|
||||||
if ( !ntfs_is_rstr_recordp( ( le32* )kaddr ) &&
|
if ( !ntfs_is_rstr_recordp( ( le32* )kaddr ) &&
|
||||||
!ntfs_is_chkd_recordp((le32*)kaddr)) {
|
!ntfs_is_chkd_recordp( ( le32* )kaddr ) )
|
||||||
|
{
|
||||||
if ( !pos )
|
if ( !pos )
|
||||||
pos = NTFS_BLOCK_SIZE >> 1;
|
pos = NTFS_BLOCK_SIZE >> 1;
|
||||||
continue;
|
continue;
|
||||||
@ -552,12 +584,14 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
|||||||
( RESTART_PAGE_HEADER* )kaddr, pos,
|
( RESTART_PAGE_HEADER* )kaddr, pos,
|
||||||
!rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
!rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
||||||
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn );
|
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn );
|
||||||
if (!err) {
|
if ( !err )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If we have now found the first (modified by chkdsk)
|
* If we have now found the first (modified by chkdsk)
|
||||||
* restart page, continue looking for the second one.
|
* restart page, continue looking for the second one.
|
||||||
*/
|
*/
|
||||||
if (!pos) {
|
if ( !pos )
|
||||||
|
{
|
||||||
pos = NTFS_BLOCK_SIZE >> 1;
|
pos = NTFS_BLOCK_SIZE >> 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -578,17 +612,20 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
|||||||
if ( !pos )
|
if ( !pos )
|
||||||
pos = NTFS_BLOCK_SIZE >> 1;
|
pos = NTFS_BLOCK_SIZE >> 1;
|
||||||
}
|
}
|
||||||
if (kaddr) {
|
if ( kaddr )
|
||||||
|
{
|
||||||
free( kaddr );
|
free( kaddr );
|
||||||
kaddr = NULL;
|
kaddr = NULL;
|
||||||
}
|
}
|
||||||
if (logfile_is_empty) {
|
if ( logfile_is_empty )
|
||||||
|
{
|
||||||
NVolSetLogFileEmpty( vol );
|
NVolSetLogFileEmpty( vol );
|
||||||
is_empty:
|
is_empty:
|
||||||
ntfs_log_trace( "Done. ($LogFile is empty.)\n" );
|
ntfs_log_trace( "Done. ($LogFile is empty.)\n" );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (!rstr1_ph) {
|
if ( !rstr1_ph )
|
||||||
|
{
|
||||||
if ( rstr2_ph )
|
if ( rstr2_ph )
|
||||||
ntfs_log_error( "BUG: rstr2_ph isn't NULL!\n" );
|
ntfs_log_error( "BUG: rstr2_ph isn't NULL!\n" );
|
||||||
ntfs_log_error( "Did not find any restart pages in "
|
ntfs_log_error( "Did not find any restart pages in "
|
||||||
@ -596,18 +633,22 @@ is_empty:
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* If both restart pages were found, use the more recent one. */
|
/* If both restart pages were found, use the more recent one. */
|
||||||
if (rstr2_ph) {
|
if ( rstr2_ph )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If the second restart area is more recent, switch to it.
|
* If the second restart area is more recent, switch to it.
|
||||||
* Otherwise just throw it away.
|
* Otherwise just throw it away.
|
||||||
*/
|
*/
|
||||||
if (rstr2_lsn > rstr1_lsn) {
|
if ( rstr2_lsn > rstr1_lsn )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Using second restart page as it is more "
|
ntfs_log_debug( "Using second restart page as it is more "
|
||||||
"recent.\n" );
|
"recent.\n" );
|
||||||
free( rstr1_ph );
|
free( rstr1_ph );
|
||||||
rstr1_ph = rstr2_ph;
|
rstr1_ph = rstr2_ph;
|
||||||
/* rstr1_lsn = rstr2_lsn; */
|
/* rstr1_lsn = rstr2_lsn; */
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_debug( "Using first restart page as it is more "
|
ntfs_log_debug( "Using first restart page as it is more "
|
||||||
"recent.\n" );
|
"recent.\n" );
|
||||||
free( rstr2_ph );
|
free( rstr2_ph );
|
||||||
@ -654,16 +695,19 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace( "Entering.\n" );
|
||||||
/* An empty $LogFile must have been clean before it got emptied. */
|
/* An empty $LogFile must have been clean before it got emptied. */
|
||||||
if (NVolLogFileEmpty(log_na->ni->vol)) {
|
if ( NVolLogFileEmpty( log_na->ni->vol ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "$LogFile is empty\n" );
|
ntfs_log_trace( "$LogFile is empty\n" );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (!rp) {
|
if ( !rp )
|
||||||
|
{
|
||||||
ntfs_log_error( "Restart page header is NULL\n" );
|
ntfs_log_error( "Restart page header is NULL\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if ( !ntfs_is_rstr_record( rp->magic ) &&
|
if ( !ntfs_is_rstr_record( rp->magic ) &&
|
||||||
!ntfs_is_chkd_record(rp->magic)) {
|
!ntfs_is_chkd_record( rp->magic ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Restart page buffer is invalid\n" );
|
ntfs_log_error( "Restart page buffer is invalid\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -675,7 +719,8 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
|||||||
* we assume there was an unclean shutdown.
|
* we assume there was an unclean shutdown.
|
||||||
*/
|
*/
|
||||||
if ( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
if ( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||||
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
|
!( ra->flags & RESTART_VOLUME_IS_CLEAN ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "The disk contains an unclean file system (%d, "
|
ntfs_log_error( "The disk contains an unclean file system (%d, "
|
||||||
"%d).\n", le16_to_cpu( ra->client_in_use_list ),
|
"%d).\n", le16_to_cpu( ra->client_in_use_list ),
|
||||||
le16_to_cpu( ra->flags ) );
|
le16_to_cpu( ra->flags ) );
|
||||||
@ -707,7 +752,8 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
|||||||
if ( NVolLogFileEmpty( na->ni->vol ) )
|
if ( NVolLogFileEmpty( na->ni->vol ) )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!NAttrNonResident(na)) {
|
if ( !NAttrNonResident( na ) )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Resident $LogFile $DATA attribute" );
|
ntfs_log_perror( "Resident $LogFile $DATA attribute" );
|
||||||
return -1;
|
return -1;
|
||||||
@ -716,13 +762,15 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
|||||||
memset( buf, -1, NTFS_BUF_SIZE );
|
memset( buf, -1, NTFS_BUF_SIZE );
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
while ((count = na->data_size - pos) > 0) {
|
while ( ( count = na->data_size - pos ) > 0 )
|
||||||
|
{
|
||||||
|
|
||||||
if ( count > NTFS_BUF_SIZE )
|
if ( count > NTFS_BUF_SIZE )
|
||||||
count = NTFS_BUF_SIZE;
|
count = NTFS_BUF_SIZE;
|
||||||
|
|
||||||
count = ntfs_attr_pwrite( na, pos, count, buf );
|
count = ntfs_attr_pwrite( na, pos, count, buf );
|
||||||
if (count <= 0) {
|
if ( count <= 0 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to reset $LogFile" );
|
ntfs_log_perror( "Failed to reset $LogFile" );
|
||||||
if ( count != -1 )
|
if ( count != -1 )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
|
@ -61,10 +61,12 @@
|
|||||||
*
|
*
|
||||||
* Begins the restart area.
|
* Begins the restart area.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
/* 0*/
|
||||||
|
NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
||||||
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||||
When creating, set this to be immediately
|
When creating, set this to be immediately
|
||||||
after this header structure (without any
|
after this header structure (without any
|
||||||
@ -108,7 +110,8 @@ typedef struct {
|
|||||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||||
* information about the log file in which they are present.
|
* information about the log file in which they are present.
|
||||||
*/
|
*/
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16( 0x0002 ),
|
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16( 0x0002 ),
|
||||||
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
|
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
|
||||||
} __attribute__( ( __packed__ ) );
|
} __attribute__( ( __packed__ ) );
|
||||||
@ -122,9 +125,11 @@ typedef le16 RESTART_AREA_FLAGS;
|
|||||||
* RESTART_PAGE_HEADER to the restart_area_offset value found in it.
|
* RESTART_PAGE_HEADER to the restart_area_offset value found in it.
|
||||||
* See notes at restart_area_offset above.
|
* See notes at restart_area_offset above.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
/* 0*/
|
||||||
|
leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||||
when the restart area was last written.
|
when the restart area was last written.
|
||||||
This happens often but what is the interval?
|
This happens often but what is the interval?
|
||||||
Is it just fixed time or is it every time a
|
Is it just fixed time or is it every time a
|
||||||
@ -262,9 +267,11 @@ typedef struct {
|
|||||||
* The offset of this record is found by adding the offset of the
|
* The offset of this record is found by adding the offset of the
|
||||||
* RESTART_AREA to the client_array_offset value found in it.
|
* RESTART_AREA to the client_array_offset value found in it.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/*Ofs*/
|
/*Ofs*/
|
||||||
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
/* 0*/
|
||||||
|
leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||||
set to 0. */
|
set to 0. */
|
||||||
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||||
the volume, i.e. the current position within
|
the volume, i.e. the current position within
|
||||||
@ -305,7 +312,8 @@ typedef struct {
|
|||||||
* following update sequence array and then aligned to 8 byte boundary, but is
|
* following update sequence array and then aligned to 8 byte boundary, but is
|
||||||
* this specified anywhere?).
|
* this specified anywhere?).
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
||||||
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||||
@ -314,15 +322,18 @@ typedef struct {
|
|||||||
alignment). */
|
alignment). */
|
||||||
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||||
|
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
LSN last_lsn;
|
LSN last_lsn;
|
||||||
s64 file_offset;
|
s64 file_offset;
|
||||||
} __attribute__( ( __packed__ ) ) copy;
|
} __attribute__( ( __packed__ ) ) copy;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
u16 page_count;
|
u16 page_count;
|
||||||
u16 page_position;
|
u16 page_position;
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
u16 next_record_offset;
|
u16 next_record_offset;
|
||||||
u8 reserved[6];
|
u8 reserved[6];
|
||||||
LSN last_end_lsn;
|
LSN last_end_lsn;
|
||||||
@ -335,7 +346,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* (Or is it log record pages?)
|
* (Or is it log record pages?)
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16( 0x0001 ), /* ??? */
|
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16( 0x0001 ), /* ??? */
|
||||||
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
||||||
/* This has nothing to do with the log record. It is only so
|
/* This has nothing to do with the log record. It is only so
|
||||||
@ -345,7 +357,8 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
u16 seq_number;
|
u16 seq_number;
|
||||||
u16 client_index;
|
u16 client_index;
|
||||||
} __attribute__( ( __packed__ ) ) LOG_CLIENT_ID;
|
} __attribute__( ( __packed__ ) ) LOG_CLIENT_ID;
|
||||||
@ -355,7 +368,8 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* Each log record seems to have a constant size of 0x70 bytes.
|
* Each log record seems to have a constant size of 0x70 bytes.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
LSN this_lsn;
|
LSN this_lsn;
|
||||||
LSN client_previous_lsn;
|
LSN client_previous_lsn;
|
||||||
LSN client_undo_next_lsn;
|
LSN client_undo_next_lsn;
|
||||||
@ -381,7 +395,8 @@ typedef struct {
|
|||||||
u32 alignment_or_reserved;
|
u32 alignment_or_reserved;
|
||||||
VCN target_vcn;
|
VCN target_vcn;
|
||||||
/* Now at ofs 0x50. */
|
/* Now at ofs 0x50. */
|
||||||
struct { /* Only present if lcns_to_follow
|
struct
|
||||||
|
{ /* Only present if lcns_to_follow
|
||||||
is not 0. */
|
is not 0. */
|
||||||
LCN lcn;
|
LCN lcn;
|
||||||
} __attribute__( ( __packed__ ) ) lcn_list[0];
|
} __attribute__( ( __packed__ ) ) lcn_list[0];
|
||||||
|
@ -67,7 +67,8 @@ static int tab;
|
|||||||
* @flags: Flags which affect the output style
|
* @flags: Flags which affect the output style
|
||||||
* @handler: Function to perform the actual logging
|
* @handler: Function to perform the actual logging
|
||||||
*/
|
*/
|
||||||
struct ntfs_logging {
|
struct ntfs_logging
|
||||||
|
{
|
||||||
u32 levels;
|
u32 levels;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
|
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
|
||||||
@ -77,7 +78,8 @@ struct ntfs_logging {
|
|||||||
* ntfs_log
|
* ntfs_log
|
||||||
* This struct controls all the logging within the library and tools.
|
* This struct controls all the logging within the library and tools.
|
||||||
*/
|
*/
|
||||||
static struct ntfs_logging ntfs_log = {
|
static struct ntfs_logging ntfs_log =
|
||||||
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
||||||
NTFS_LOG_LEVEL_LEAVE |
|
NTFS_LOG_LEVEL_LEAVE |
|
||||||
@ -201,7 +203,8 @@ static FILE * ntfs_log_get_stream(u32 level)
|
|||||||
{
|
{
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
|
|
||||||
switch (level) {
|
switch ( level )
|
||||||
|
{
|
||||||
case NTFS_LOG_LEVEL_INFO:
|
case NTFS_LOG_LEVEL_INFO:
|
||||||
case NTFS_LOG_LEVEL_QUIET:
|
case NTFS_LOG_LEVEL_QUIET:
|
||||||
case NTFS_LOG_LEVEL_PROGRESS:
|
case NTFS_LOG_LEVEL_PROGRESS:
|
||||||
@ -237,7 +240,8 @@ static const char * ntfs_log_get_prefix(u32 level)
|
|||||||
{
|
{
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
|
|
||||||
switch (level) {
|
switch ( level )
|
||||||
|
{
|
||||||
case NTFS_LOG_LEVEL_DEBUG:
|
case NTFS_LOG_LEVEL_DEBUG:
|
||||||
prefix = "DEBUG: ";
|
prefix = "DEBUG: ";
|
||||||
break;
|
break;
|
||||||
@ -286,13 +290,15 @@ static const char * ntfs_log_get_prefix(u32 level)
|
|||||||
*/
|
*/
|
||||||
void ntfs_log_set_handler( ntfs_log_handler *handler )
|
void ntfs_log_set_handler( ntfs_log_handler *handler )
|
||||||
{
|
{
|
||||||
if (handler) {
|
if ( handler )
|
||||||
|
{
|
||||||
ntfs_log.handler = handler;
|
ntfs_log.handler = handler;
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
if ( handler == ntfs_log_handler_syslog )
|
if ( handler == ntfs_log_handler_syslog )
|
||||||
openlog( "ntfs-3g", LOG_PID, LOG_USER );
|
openlog( "ntfs-3g", LOG_PID, LOG_USER );
|
||||||
#endif
|
#endif
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ntfs_log.handler = ntfs_log_handler_null;
|
ntfs_log.handler = ntfs_log_handler_null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,13 +375,15 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
|||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
ret = vsnprintf( logbuf, LOG_LINE_LEN, format, args );
|
ret = vsnprintf( logbuf, LOG_LINE_LEN, format, args );
|
||||||
if (ret < 0) {
|
if ( ret < 0 )
|
||||||
|
{
|
||||||
vsyslog( LOG_NOTICE, format, args );
|
vsyslog( LOG_NOTICE, format, args );
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
if ( ( LOG_LINE_LEN > ret + 3 ) && ( level & NTFS_LOG_LEVEL_PERROR ) )
|
||||||
|
{
|
||||||
strncat( logbuf, ": ", LOG_LINE_LEN - ret - 1 );
|
strncat( logbuf, ": ", LOG_LINE_LEN - ret - 1 );
|
||||||
strncat( logbuf, strerror( olderr ), LOG_LINE_LEN - ( ret + 3 ) );
|
strncat( logbuf, strerror( olderr ), LOG_LINE_LEN - ( ret + 3 ) );
|
||||||
ret = strlen( logbuf );
|
ret = strlen( logbuf );
|
||||||
@ -424,7 +432,8 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
|||||||
stream = ( FILE* )data;
|
stream = ( FILE* )data;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (level == NTFS_LOG_LEVEL_LEAVE) {
|
if ( level == NTFS_LOG_LEVEL_LEAVE )
|
||||||
|
{
|
||||||
if ( tab )
|
if ( tab )
|
||||||
tab--;
|
tab--;
|
||||||
return 0;
|
return 0;
|
||||||
@ -593,16 +602,23 @@ int ntfs_log_handler_stderr(const char *function, const char *file,
|
|||||||
*/
|
*/
|
||||||
BOOL ntfs_log_parse_option( const char *option )
|
BOOL ntfs_log_parse_option( const char *option )
|
||||||
{
|
{
|
||||||
if (strcmp(option, "--log-debug") == 0) {
|
if ( strcmp( option, "--log-debug" ) == 0 )
|
||||||
|
{
|
||||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_DEBUG );
|
ntfs_log_set_levels( NTFS_LOG_LEVEL_DEBUG );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else if (strcmp(option, "--log-verbose") == 0) {
|
}
|
||||||
|
else if ( strcmp( option, "--log-verbose" ) == 0 )
|
||||||
|
{
|
||||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_VERBOSE );
|
ntfs_log_set_levels( NTFS_LOG_LEVEL_VERBOSE );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else if (strcmp(option, "--log-quiet") == 0) {
|
}
|
||||||
|
else if ( strcmp( option, "--log-quiet" ) == 0 )
|
||||||
|
{
|
||||||
ntfs_log_clear_levels( NTFS_LOG_LEVEL_QUIET );
|
ntfs_log_clear_levels( NTFS_LOG_LEVEL_QUIET );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else if (strcmp(option, "--log-trace") == 0) {
|
}
|
||||||
|
else if ( strcmp( option, "--log-trace" ) == 0 )
|
||||||
|
{
|
||||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_TRACE );
|
ntfs_log_set_levels( NTFS_LOG_LEVEL_TRACE );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,13 @@
|
|||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
static inline void* ntfs_alloc (size_t size) {
|
static inline void* ntfs_alloc ( size_t size )
|
||||||
|
{
|
||||||
return malloc( size );
|
return malloc( size );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void* ntfs_align (size_t size) {
|
static inline void* ntfs_align ( size_t size )
|
||||||
|
{
|
||||||
#ifdef __wii__
|
#ifdef __wii__
|
||||||
return memalign( 32, size );
|
return memalign( 32, size );
|
||||||
#else
|
#else
|
||||||
@ -36,7 +38,8 @@ static inline void* ntfs_align (size_t size) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ntfs_free (void* mem) {
|
static inline void ntfs_free ( void* mem )
|
||||||
|
{
|
||||||
free( mem );
|
free( mem );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,8 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
|
|
||||||
ntfs_log_trace( "inode %llu\n", ( unsigned long long )MREF( mref ) );
|
ntfs_log_trace( "inode %llu\n", ( unsigned long long )MREF( mref ) );
|
||||||
|
|
||||||
if (!vol || !vol->mft_na || !b || count < 0) {
|
if ( !vol || !vol->mft_na || !b || count < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: b=%p count=%lld mft=%llu", __FUNCTION__,
|
ntfs_log_perror( "%s: b=%p count=%lld mft=%llu", __FUNCTION__,
|
||||||
b, ( long long )count, ( unsigned long long )MREF( mref ) );
|
b, ( long long )count, ( unsigned long long )MREF( mref ) );
|
||||||
@ -95,7 +96,8 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
m = MREF( mref );
|
m = MREF( mref );
|
||||||
/* Refuse to read non-allocated mft records. */
|
/* Refuse to read non-allocated mft records. */
|
||||||
if ( m + count > vol->mft_na->initialized_size >>
|
if ( m + count > vol->mft_na->initialized_size >>
|
||||||
vol->mft_record_size_bits) {
|
vol->mft_record_size_bits )
|
||||||
|
{
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror( "Trying to read non-allocated mft records "
|
ntfs_log_perror( "Trying to read non-allocated mft records "
|
||||||
"(%lld > %lld)", ( long long )m + count,
|
"(%lld > %lld)", ( long long )m + count,
|
||||||
@ -105,7 +107,8 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
}
|
}
|
||||||
br = ntfs_attr_mst_pread( vol->mft_na, m << vol->mft_record_size_bits,
|
br = ntfs_attr_mst_pread( vol->mft_na, m << vol->mft_record_size_bits,
|
||||||
count, vol->mft_record_size, b );
|
count, vol->mft_record_size, b );
|
||||||
if (br != count) {
|
if ( br != count )
|
||||||
|
{
|
||||||
if ( br != -1 )
|
if ( br != -1 )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Failed to read of MFT, mft=%llu count=%lld "
|
ntfs_log_perror( "Failed to read of MFT, mft=%llu count=%lld "
|
||||||
@ -148,14 +151,16 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
void *bmirr = NULL;
|
void *bmirr = NULL;
|
||||||
int cnt = 0, res = 0;
|
int cnt = 0, res = 0;
|
||||||
|
|
||||||
if (!vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0) {
|
if ( !vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
m = MREF( mref );
|
m = MREF( mref );
|
||||||
/* Refuse to write non-allocated mft records. */
|
/* Refuse to write non-allocated mft records. */
|
||||||
if ( m + count > vol->mft_na->initialized_size >>
|
if ( m + count > vol->mft_na->initialized_size >>
|
||||||
vol->mft_record_size_bits) {
|
vol->mft_record_size_bits )
|
||||||
|
{
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror( "Trying to write non-allocated mft records "
|
ntfs_log_perror( "Trying to write non-allocated mft records "
|
||||||
"(%lld > %lld)", ( long long )m + count,
|
"(%lld > %lld)", ( long long )m + count,
|
||||||
@ -163,8 +168,10 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
vol->mft_record_size_bits );
|
vol->mft_record_size_bits );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (m < vol->mftmirr_size) {
|
if ( m < vol->mftmirr_size )
|
||||||
if (!vol->mftmirr_na) {
|
{
|
||||||
|
if ( !vol->mftmirr_na )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -178,7 +185,8 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
}
|
}
|
||||||
bw = ntfs_attr_mst_pwrite( vol->mft_na, m << vol->mft_record_size_bits,
|
bw = ntfs_attr_mst_pwrite( vol->mft_na, m << vol->mft_record_size_bits,
|
||||||
count, vol->mft_record_size, b );
|
count, vol->mft_record_size, b );
|
||||||
if (bw != count) {
|
if ( bw != count )
|
||||||
|
{
|
||||||
if ( bw != -1 )
|
if ( bw != -1 )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
if ( bw >= 0 )
|
if ( bw >= 0 )
|
||||||
@ -188,13 +196,15 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
ntfs_log_perror( "Error writing $Mft record(s)" );
|
ntfs_log_perror( "Error writing $Mft record(s)" );
|
||||||
res = errno;
|
res = errno;
|
||||||
}
|
}
|
||||||
if (bmirr && bw > 0) {
|
if ( bmirr && bw > 0 )
|
||||||
|
{
|
||||||
if ( bw < cnt )
|
if ( bw < cnt )
|
||||||
cnt = bw;
|
cnt = bw;
|
||||||
bw = ntfs_attr_mst_pwrite( vol->mftmirr_na,
|
bw = ntfs_attr_mst_pwrite( vol->mftmirr_na,
|
||||||
m << vol->mft_record_size_bits, cnt,
|
m << vol->mft_record_size_bits, cnt,
|
||||||
vol->mft_record_size, bmirr );
|
vol->mft_record_size, bmirr );
|
||||||
if (bw != cnt) {
|
if ( bw != cnt )
|
||||||
|
{
|
||||||
if ( bw != -1 )
|
if ( bw != -1 )
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_debug( "Error: failed to sync $MFTMirr! Run "
|
ntfs_log_debug( "Error: failed to sync $MFTMirr! Run "
|
||||||
@ -215,13 +225,15 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
ATTR_RECORD *a;
|
ATTR_RECORD *a;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (!ntfs_is_file_record(m->magic)) {
|
if ( !ntfs_is_file_record( m->magic ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Record %llu has no FILE magic (0x%x)\n",
|
ntfs_log_error( "Record %llu has no FILE magic (0x%x)\n",
|
||||||
( unsigned long long )MREF( mref ), *( le32 * )m );
|
( unsigned long long )MREF( mref ), *( le32 * )m );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (le32_to_cpu(m->bytes_allocated) != vol->mft_record_size) {
|
if ( le32_to_cpu( m->bytes_allocated ) != vol->mft_record_size )
|
||||||
|
{
|
||||||
ntfs_log_error( "Record %llu has corrupt allocation size "
|
ntfs_log_error( "Record %llu has corrupt allocation size "
|
||||||
"(%u <> %u)\n", ( unsigned long long )MREF( mref ),
|
"(%u <> %u)\n", ( unsigned long long )MREF( mref ),
|
||||||
vol->mft_record_size,
|
vol->mft_record_size,
|
||||||
@ -230,7 +242,8 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
}
|
}
|
||||||
|
|
||||||
a = ( ATTR_RECORD * )( ( char * )m + le16_to_cpu( m->attrs_offset ) );
|
a = ( ATTR_RECORD * )( ( char * )m + le16_to_cpu( m->attrs_offset ) );
|
||||||
if (p2n(a) < p2n(m) || (char *)a > (char *)m + vol->mft_record_size) {
|
if ( p2n( a ) < p2n( m ) || ( char * )a > ( char * )m + vol->mft_record_size )
|
||||||
|
{
|
||||||
ntfs_log_error( "Record %llu is corrupt\n",
|
ntfs_log_error( "Record %llu is corrupt\n",
|
||||||
( unsigned long long )MREF( mref ) );
|
( unsigned long long )MREF( mref ) );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -279,14 +292,16 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
{
|
{
|
||||||
MFT_RECORD *m;
|
MFT_RECORD *m;
|
||||||
|
|
||||||
if (!vol || !mrec) {
|
if ( !vol || !mrec )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
|
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m = *mrec;
|
m = *mrec;
|
||||||
if (!m) {
|
if ( !m )
|
||||||
|
{
|
||||||
m = ntfs_malloc( vol->mft_record_size );
|
m = ntfs_malloc( vol->mft_record_size );
|
||||||
if ( !m )
|
if ( !m )
|
||||||
return -1;
|
return -1;
|
||||||
@ -297,7 +312,8 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
if ( ntfs_mft_record_check( vol, mref, m ) )
|
if ( ntfs_mft_record_check( vol, mref, m ) )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number)) {
|
if ( MSEQNO( mref ) && MSEQNO( mref ) != le16_to_cpu( m->sequence_number ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Record %llu has wrong SeqNo (%d <> %d)\n",
|
ntfs_log_error( "Record %llu has wrong SeqNo (%d <> %d)\n",
|
||||||
( unsigned long long )MREF( mref ), MSEQNO( mref ),
|
( unsigned long long )MREF( mref ), MSEQNO( mref ),
|
||||||
le16_to_cpu( m->sequence_number ) );
|
le16_to_cpu( m->sequence_number ) );
|
||||||
@ -332,7 +348,8 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
{
|
{
|
||||||
ATTR_RECORD *a;
|
ATTR_RECORD *a;
|
||||||
|
|
||||||
if (!vol || !mrec) {
|
if ( !vol || !mrec )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
|
ntfs_log_perror( "%s: mrec=%p", __FUNCTION__, mrec );
|
||||||
return -1;
|
return -1;
|
||||||
@ -340,9 +357,11 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
/* Aligned to 2-byte boundary. */
|
/* Aligned to 2-byte boundary. */
|
||||||
if ( vol->major_ver < 3 || ( vol->major_ver == 3 && !vol->minor_ver ) )
|
if ( vol->major_ver < 3 || ( vol->major_ver == 3 && !vol->minor_ver ) )
|
||||||
mrec->usa_ofs = cpu_to_le16( ( sizeof( MFT_RECORD_OLD ) + 1 ) & ~1 );
|
mrec->usa_ofs = cpu_to_le16( ( sizeof( MFT_RECORD_OLD ) + 1 ) & ~1 );
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* Abort if mref is > 32 bits. */
|
/* Abort if mref is > 32 bits. */
|
||||||
if (MREF(mref) & 0x0000ffff00000000ull) {
|
if ( MREF( mref ) & 0x0000ffff00000000ull )
|
||||||
|
{
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
ntfs_log_perror( "Mft reference exceeds 32 bits" );
|
ntfs_log_perror( "Mft reference exceeds 32 bits" );
|
||||||
return -1;
|
return -1;
|
||||||
@ -359,7 +378,8 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
|||||||
if ( vol->mft_record_size >= NTFS_BLOCK_SIZE )
|
if ( vol->mft_record_size >= NTFS_BLOCK_SIZE )
|
||||||
mrec->usa_count = cpu_to_le16( vol->mft_record_size /
|
mrec->usa_count = cpu_to_le16( vol->mft_record_size /
|
||||||
NTFS_BLOCK_SIZE + 1 );
|
NTFS_BLOCK_SIZE + 1 );
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
mrec->usa_count = cpu_to_le16( 1 );
|
mrec->usa_count = cpu_to_le16( 1 );
|
||||||
ntfs_log_error( "Sector size is bigger than MFT record size. "
|
ntfs_log_error( "Sector size is bigger than MFT record size. "
|
||||||
"Setting usa_count to 1. If Windows chkdsk "
|
"Setting usa_count to 1. If Windows chkdsk "
|
||||||
@ -502,16 +522,19 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||||||
data_pos = base_ni->mft_no + 1;
|
data_pos = base_ni->mft_no + 1;
|
||||||
if ( data_pos < RESERVED_MFT_RECORDS )
|
if ( data_pos < RESERVED_MFT_RECORDS )
|
||||||
data_pos = RESERVED_MFT_RECORDS;
|
data_pos = RESERVED_MFT_RECORDS;
|
||||||
if (data_pos >= pass_end) {
|
if ( data_pos >= pass_end )
|
||||||
|
{
|
||||||
data_pos = RESERVED_MFT_RECORDS;
|
data_pos = RESERVED_MFT_RECORDS;
|
||||||
pass = 2;
|
pass = 2;
|
||||||
/* This happens on a freshly formatted volume. */
|
/* This happens on a freshly formatted volume. */
|
||||||
if (data_pos >= pass_end) {
|
if ( data_pos >= pass_end )
|
||||||
|
{
|
||||||
errno = ENOSPC;
|
errno = ENOSPC;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ntfs_is_mft(base_ni)) {
|
if ( ntfs_is_mft( base_ni ) )
|
||||||
|
{
|
||||||
data_pos = 0;
|
data_pos = 0;
|
||||||
pass = 2;
|
pass = 2;
|
||||||
}
|
}
|
||||||
@ -529,21 +552,24 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||||||
b = 0;
|
b = 0;
|
||||||
#endif
|
#endif
|
||||||
/* Loop until a free mft record is found. */
|
/* Loop until a free mft record is found. */
|
||||||
for (; pass <= 2; size = PAGE_SIZE) {
|
for ( ; pass <= 2; size = PAGE_SIZE )
|
||||||
|
{
|
||||||
/* Cap size to pass_end. */
|
/* Cap size to pass_end. */
|
||||||
ofs = data_pos >> 3;
|
ofs = data_pos >> 3;
|
||||||
ll = ( ( pass_end + 7 ) >> 3 ) - ofs;
|
ll = ( ( pass_end + 7 ) >> 3 ) - ofs;
|
||||||
if ( size > ll )
|
if ( size > ll )
|
||||||
size = ll;
|
size = ll;
|
||||||
ll = ntfs_attr_pread( mftbmp_na, ofs, size, buf );
|
ll = ntfs_attr_pread( mftbmp_na, ofs, size, buf );
|
||||||
if (ll < 0) {
|
if ( ll < 0 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to read $MFT bitmap" );
|
ntfs_log_perror( "Failed to read $MFT bitmap" );
|
||||||
free( buf );
|
free( buf );
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
ntfs_log_debug( "Read 0x%llx bytes.\n", ( long long )ll );
|
ntfs_log_debug( "Read 0x%llx bytes.\n", ( long long )ll );
|
||||||
/* If we read at least one byte, search @buf for a zero bit. */
|
/* If we read at least one byte, search @buf for a zero bit. */
|
||||||
if (ll) {
|
if ( ll )
|
||||||
|
{
|
||||||
size = ll << 3;
|
size = ll << 3;
|
||||||
bit = data_pos & 7;
|
bit = data_pos & 7;
|
||||||
data_pos &= ~7ull;
|
data_pos &= ~7ull;
|
||||||
@ -553,7 +579,8 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||||||
( long long )data_pos, ( long long )bit,
|
( long long )data_pos, ( long long )bit,
|
||||||
byte ? *byte : -1, b );
|
byte ? *byte : -1, b );
|
||||||
for ( ; bit < size && data_pos + bit < pass_end;
|
for ( ; bit < size && data_pos + bit < pass_end;
|
||||||
bit &= ~7ull, bit += 8) {
|
bit &= ~7ull, bit += 8 )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If we're extending $MFT and running out of the first
|
* If we're extending $MFT and running out of the first
|
||||||
* mft record (base record) then give up searching since
|
* mft record (base record) then give up searching since
|
||||||
@ -568,7 +595,8 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||||||
|
|
||||||
/* Note: ffz() result must be zero based. */
|
/* Note: ffz() result must be zero based. */
|
||||||
b = ntfs_ffz( ( unsigned long ) * byte );
|
b = ntfs_ffz( ( unsigned long ) * byte );
|
||||||
if (b < 8 && b >= (bit & 7)) {
|
if ( b < 8 && b >= ( bit & 7 ) )
|
||||||
|
{
|
||||||
free( buf );
|
free( buf );
|
||||||
ret = data_pos + ( bit & ~7ull ) + b;
|
ret = data_pos + ( bit & ~7ull ) + b;
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -589,7 +617,8 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||||||
}
|
}
|
||||||
/* Do the next pass. */
|
/* Do the next pass. */
|
||||||
pass++;
|
pass++;
|
||||||
if (pass == 2) {
|
if ( pass == 2 )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Starting the second pass, in which we scan the first
|
* Starting the second pass, in which we scan the first
|
||||||
* part of the zone which we omitted earlier.
|
* part of the zone which we omitted earlier.
|
||||||
@ -617,8 +646,10 @@ static int ntfs_mft_attr_extend(ntfs_attr *na)
|
|||||||
int ret = STATUS_ERROR;
|
int ret = STATUS_ERROR;
|
||||||
ntfs_log_enter( "Entering\n" );
|
ntfs_log_enter( "Entering\n" );
|
||||||
|
|
||||||
if (!NInoAttrList(na->ni)) {
|
if ( !NInoAttrList( na->ni ) )
|
||||||
if (ntfs_inode_add_attrlist(na->ni)) {
|
{
|
||||||
|
if ( ntfs_inode_add_attrlist( na->ni ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "%s: Can not add attrlist #3", __FUNCTION__ );
|
ntfs_log_perror( "%s: Can not add attrlist #3", __FUNCTION__ );
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -627,7 +658,8 @@ static int ntfs_mft_attr_extend(ntfs_attr *na)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntfs_attr_update_mapping_pairs(na, 0)) {
|
if ( ntfs_attr_update_mapping_pairs( na, 0 ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
|
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -663,7 +695,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
*/
|
*/
|
||||||
rl = ntfs_attr_find_vcn( mftbmp_na, ( mftbmp_na->allocated_size - 1 ) >>
|
rl = ntfs_attr_find_vcn( mftbmp_na, ( mftbmp_na->allocated_size - 1 ) >>
|
||||||
vol->cluster_size_bits );
|
vol->cluster_size_bits );
|
||||||
if (!rl || !rl->length || rl->lcn < 0) {
|
if ( !rl || !rl->length || rl->lcn < 0 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to determine last allocated "
|
ntfs_log_error( "Failed to determine last allocated "
|
||||||
"cluster of mft bitmap attribute.\n" );
|
"cluster of mft bitmap attribute.\n" );
|
||||||
if ( rl )
|
if ( rl )
|
||||||
@ -673,13 +706,15 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
lcn = rl->lcn + rl->length;
|
lcn = rl->lcn + rl->length;
|
||||||
|
|
||||||
rl2 = ntfs_cluster_alloc( vol, rl[1].vcn, 1, lcn, DATA_ZONE );
|
rl2 = ntfs_cluster_alloc( vol, rl[1].vcn, 1, lcn, DATA_ZONE );
|
||||||
if (!rl2) {
|
if ( !rl2 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to allocate a cluster for "
|
ntfs_log_error( "Failed to allocate a cluster for "
|
||||||
"the mft bitmap.\n" );
|
"the mft bitmap.\n" );
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
rl = ntfs_runlists_merge( mftbmp_na->rl, rl2 );
|
rl = ntfs_runlists_merge( mftbmp_na->rl, rl2 );
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_error( "Failed to merge runlists for mft "
|
ntfs_log_error( "Failed to merge runlists for mft "
|
||||||
"bitmap.\n" );
|
"bitmap.\n" );
|
||||||
@ -704,7 +739,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
goto undo_alloc;
|
goto undo_alloc;
|
||||||
|
|
||||||
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
||||||
mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) {
|
mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find last attribute extent of "
|
ntfs_log_error( "Failed to find last attribute extent of "
|
||||||
"mft bitmap attribute.\n" );
|
"mft bitmap attribute.\n" );
|
||||||
goto undo_alloc;
|
goto undo_alloc;
|
||||||
@ -713,7 +749,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
a = ctx->attr;
|
a = ctx->attr;
|
||||||
ll = sle64_to_cpu( a->lowest_vcn );
|
ll = sle64_to_cpu( a->lowest_vcn );
|
||||||
rl2 = ntfs_attr_find_vcn( mftbmp_na, ll );
|
rl2 = ntfs_attr_find_vcn( mftbmp_na, ll );
|
||||||
if (!rl2 || !rl2->length) {
|
if ( !rl2 || !rl2->length )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to determine previous last "
|
ntfs_log_error( "Failed to determine previous last "
|
||||||
"allocated cluster of mft bitmap attribute.\n" );
|
"allocated cluster of mft bitmap attribute.\n" );
|
||||||
if ( rl2 )
|
if ( rl2 )
|
||||||
@ -722,7 +759,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
}
|
}
|
||||||
/* Get the size for the new mapping pairs array for this extent. */
|
/* Get the size for the new mapping pairs array for this extent. */
|
||||||
mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX );
|
mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX );
|
||||||
if (mp_size <= 0) {
|
if ( mp_size <= 0 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Get size for mapping pairs failed for "
|
ntfs_log_error( "Get size for mapping pairs failed for "
|
||||||
"mft bitmap attribute extent.\n" );
|
"mft bitmap attribute extent.\n" );
|
||||||
goto undo_alloc;
|
goto undo_alloc;
|
||||||
@ -730,12 +768,14 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
/* Expand the attribute record if necessary. */
|
/* Expand the attribute record if necessary. */
|
||||||
old_alen = le32_to_cpu( a->length );
|
old_alen = le32_to_cpu( a->length );
|
||||||
if ( ntfs_attr_record_resize( m, a, mp_size +
|
if ( ntfs_attr_record_resize( m, a, mp_size +
|
||||||
le16_to_cpu(a->mapping_pairs_offset))) {
|
le16_to_cpu( a->mapping_pairs_offset ) ) )
|
||||||
|
{
|
||||||
ntfs_log_info( "extending $MFT bitmap\n" );
|
ntfs_log_info( "extending $MFT bitmap\n" );
|
||||||
ret = ntfs_mft_attr_extend( vol->mftbmp_na );
|
ret = ntfs_mft_attr_extend( vol->mftbmp_na );
|
||||||
if ( ret == STATUS_OK )
|
if ( ret == STATUS_OK )
|
||||||
goto ok;
|
goto ok;
|
||||||
if (ret == STATUS_ERROR) {
|
if ( ret == STATUS_ERROR )
|
||||||
|
{
|
||||||
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
|
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
|
||||||
update_mp = TRUE;
|
update_mp = TRUE;
|
||||||
}
|
}
|
||||||
@ -745,7 +785,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
/* Generate the mapping pairs array directly into the attr record. */
|
/* Generate the mapping pairs array directly into the attr record. */
|
||||||
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
||||||
le16_to_cpu( a->mapping_pairs_offset ), mp_size, rl2, ll,
|
le16_to_cpu( a->mapping_pairs_offset ), mp_size, rl2, ll,
|
||||||
NULL)) {
|
NULL ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to build mapping pairs array for "
|
ntfs_log_error( "Failed to build mapping pairs array for "
|
||||||
"mft bitmap attribute.\n" );
|
"mft bitmap attribute.\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -757,7 +798,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
* We now have extended the mft bitmap allocated_size by one cluster.
|
* We now have extended the mft bitmap allocated_size by one cluster.
|
||||||
* Reflect this in the ntfs_attr structure and the attribute record.
|
* Reflect this in the ntfs_attr structure and the attribute record.
|
||||||
*/
|
*/
|
||||||
if (a->lowest_vcn) {
|
if ( a->lowest_vcn )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* We are not in the first attribute extent, switch to it, but
|
* We are not in the first attribute extent, switch to it, but
|
||||||
* first ensure the changes will make it to disk later.
|
* first ensure the changes will make it to disk later.
|
||||||
@ -765,7 +807,8 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
|
|||||||
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
||||||
mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {
|
mftbmp_na->name_len, 0, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find first attribute "
|
ntfs_log_error( "Failed to find first attribute "
|
||||||
"extent of mft bitmap attribute.\n" );
|
"extent of mft bitmap attribute.\n" );
|
||||||
goto restore_undo_alloc;
|
goto restore_undo_alloc;
|
||||||
@ -784,7 +827,8 @@ restore_undo_alloc:
|
|||||||
err = errno;
|
err = errno;
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
||||||
mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) {
|
mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find last attribute extent of "
|
ntfs_log_error( "Failed to find last attribute extent of "
|
||||||
"mft bitmap attribute.%s\n", es );
|
"mft bitmap attribute.%s\n", es );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
@ -813,7 +857,8 @@ undo_alloc:
|
|||||||
ntfs_log_error( "Failed to free cluster.%s\n", es );
|
ntfs_log_error( "Failed to free cluster.%s\n", es );
|
||||||
else
|
else
|
||||||
vol->free_clusters++;
|
vol->free_clusters++;
|
||||||
if (mp_rebuilt) {
|
if ( mp_rebuilt )
|
||||||
|
{
|
||||||
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
||||||
le16_to_cpu( a->mapping_pairs_offset ),
|
le16_to_cpu( a->mapping_pairs_offset ),
|
||||||
old_alen - le16_to_cpu( a->mapping_pairs_offset ),
|
old_alen - le16_to_cpu( a->mapping_pairs_offset ),
|
||||||
@ -825,7 +870,8 @@ undo_alloc:
|
|||||||
"record.%s\n", es );
|
"record.%s\n", es );
|
||||||
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
||||||
}
|
}
|
||||||
if (update_mp) {
|
if ( update_mp )
|
||||||
|
{
|
||||||
if ( ntfs_attr_update_mapping_pairs( vol->mftbmp_na, 0 ) )
|
if ( ntfs_attr_update_mapping_pairs( vol->mftbmp_na, 0 ) )
|
||||||
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
|
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
|
||||||
}
|
}
|
||||||
@ -884,7 +930,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
||||||
mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {
|
mftbmp_na->name_len, 0, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find first attribute extent of "
|
ntfs_log_error( "Failed to find first attribute extent of "
|
||||||
"mft bitmap attribute.\n" );
|
"mft bitmap attribute.\n" );
|
||||||
err = errno;
|
err = errno;
|
||||||
@ -895,7 +942,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
|||||||
old_initialized_size = mftbmp_na->initialized_size;
|
old_initialized_size = mftbmp_na->initialized_size;
|
||||||
mftbmp_na->initialized_size += 8;
|
mftbmp_na->initialized_size += 8;
|
||||||
a->initialized_size = cpu_to_sle64( mftbmp_na->initialized_size );
|
a->initialized_size = cpu_to_sle64( mftbmp_na->initialized_size );
|
||||||
if (mftbmp_na->initialized_size > mftbmp_na->data_size) {
|
if ( mftbmp_na->initialized_size > mftbmp_na->data_size )
|
||||||
|
{
|
||||||
mftbmp_na->data_size = mftbmp_na->initialized_size;
|
mftbmp_na->data_size = mftbmp_na->initialized_size;
|
||||||
a->data_size = cpu_to_sle64( mftbmp_na->data_size );
|
a->data_size = cpu_to_sle64( mftbmp_na->data_size );
|
||||||
}
|
}
|
||||||
@ -905,7 +953,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
|||||||
/* Initialize the mft bitmap attribute value with zeroes. */
|
/* Initialize the mft bitmap attribute value with zeroes. */
|
||||||
ll = 0;
|
ll = 0;
|
||||||
ll = ntfs_attr_pwrite( mftbmp_na, old_initialized_size, 8, &ll );
|
ll = ntfs_attr_pwrite( mftbmp_na, old_initialized_size, 8, &ll );
|
||||||
if (ll == 8) {
|
if ( ll == 8 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Wrote eight initialized bytes to mft bitmap.\n" );
|
ntfs_log_debug( "Wrote eight initialized bytes to mft bitmap.\n" );
|
||||||
vol->free_mft_records += ( 8 * 8 );
|
vol->free_mft_records += ( 8 * 8 );
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -921,7 +970,8 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
if ( ntfs_attr_lookup( mftbmp_na->type, mftbmp_na->name,
|
||||||
mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {
|
mftbmp_na->name_len, 0, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find first attribute extent of "
|
ntfs_log_error( "Failed to find first attribute extent of "
|
||||||
"mft bitmap attribute.%s\n", es );
|
"mft bitmap attribute.%s\n", es );
|
||||||
put_err_out:
|
put_err_out:
|
||||||
@ -931,7 +981,8 @@ put_err_out:
|
|||||||
a = ctx->attr;
|
a = ctx->attr;
|
||||||
mftbmp_na->initialized_size = old_initialized_size;
|
mftbmp_na->initialized_size = old_initialized_size;
|
||||||
a->initialized_size = cpu_to_sle64( old_initialized_size );
|
a->initialized_size = cpu_to_sle64( old_initialized_size );
|
||||||
if (mftbmp_na->data_size != old_data_size) {
|
if ( mftbmp_na->data_size != old_data_size )
|
||||||
|
{
|
||||||
mftbmp_na->data_size = old_data_size;
|
mftbmp_na->data_size = old_data_size;
|
||||||
a->data_size = cpu_to_sle64( old_data_size );
|
a->data_size = cpu_to_sle64( old_data_size );
|
||||||
}
|
}
|
||||||
@ -989,7 +1040,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
rl = ntfs_attr_find_vcn( mft_na,
|
rl = ntfs_attr_find_vcn( mft_na,
|
||||||
( mft_na->allocated_size - 1 ) >> vol->cluster_size_bits );
|
( mft_na->allocated_size - 1 ) >> vol->cluster_size_bits );
|
||||||
|
|
||||||
if (!rl || !rl->length || rl->lcn < 0) {
|
if ( !rl || !rl->length || rl->lcn < 0 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to determine last allocated "
|
ntfs_log_error( "Failed to determine last allocated "
|
||||||
"cluster of mft data attribute.\n" );
|
"cluster of mft data attribute.\n" );
|
||||||
if ( rl )
|
if ( rl )
|
||||||
@ -1009,11 +1061,13 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
nr = min_nr;
|
nr = min_nr;
|
||||||
|
|
||||||
old_last_vcn = rl[1].vcn;
|
old_last_vcn = rl[1].vcn;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
rl2 = ntfs_cluster_alloc( vol, old_last_vcn, nr, lcn, MFT_ZONE );
|
rl2 = ntfs_cluster_alloc( vol, old_last_vcn, nr, lcn, MFT_ZONE );
|
||||||
if ( rl2 )
|
if ( rl2 )
|
||||||
break;
|
break;
|
||||||
if (errno != ENOSPC || nr == min_nr) {
|
if ( errno != ENOSPC || nr == min_nr )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to allocate (%lld) clusters "
|
ntfs_log_perror( "Failed to allocate (%lld) clusters "
|
||||||
"for $MFT", ( long long )nr );
|
"for $MFT", ( long long )nr );
|
||||||
goto out;
|
goto out;
|
||||||
@ -1026,12 +1080,14 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
nr = min_nr;
|
nr = min_nr;
|
||||||
ntfs_log_debug( "Retrying mft data allocation with minimal cluster "
|
ntfs_log_debug( "Retrying mft data allocation with minimal cluster "
|
||||||
"count %lli.\n", ( long long )nr );
|
"count %lli.\n", ( long long )nr );
|
||||||
} while (1);
|
}
|
||||||
|
while ( 1 );
|
||||||
|
|
||||||
ntfs_log_debug( "Allocated %lld clusters.\n", ( long long )nr );
|
ntfs_log_debug( "Allocated %lld clusters.\n", ( long long )nr );
|
||||||
|
|
||||||
rl = ntfs_runlists_merge( mft_na->rl, rl2 );
|
rl = ntfs_runlists_merge( mft_na->rl, rl2 );
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_error( "Failed to merge runlists for mft data "
|
ntfs_log_error( "Failed to merge runlists for mft data "
|
||||||
"attribute.\n" );
|
"attribute.\n" );
|
||||||
@ -1053,7 +1109,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
goto undo_alloc;
|
goto undo_alloc;
|
||||||
|
|
||||||
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||||
rl[1].vcn, NULL, 0, ctx)) {
|
rl[1].vcn, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find last attribute extent of "
|
ntfs_log_error( "Failed to find last attribute extent of "
|
||||||
"mft data attribute.\n" );
|
"mft data attribute.\n" );
|
||||||
goto undo_alloc;
|
goto undo_alloc;
|
||||||
@ -1062,7 +1119,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
a = ctx->attr;
|
a = ctx->attr;
|
||||||
ll = sle64_to_cpu( a->lowest_vcn );
|
ll = sle64_to_cpu( a->lowest_vcn );
|
||||||
rl2 = ntfs_attr_find_vcn( mft_na, ll );
|
rl2 = ntfs_attr_find_vcn( mft_na, ll );
|
||||||
if (!rl2 || !rl2->length) {
|
if ( !rl2 || !rl2->length )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to determine previous last "
|
ntfs_log_error( "Failed to determine previous last "
|
||||||
"allocated cluster of mft data attribute.\n" );
|
"allocated cluster of mft data attribute.\n" );
|
||||||
if ( rl2 )
|
if ( rl2 )
|
||||||
@ -1071,7 +1129,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
}
|
}
|
||||||
/* Get the size for the new mapping pairs array for this extent. */
|
/* Get the size for the new mapping pairs array for this extent. */
|
||||||
mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX );
|
mp_size = ntfs_get_size_for_mapping_pairs( vol, rl2, ll, INT_MAX );
|
||||||
if (mp_size <= 0) {
|
if ( mp_size <= 0 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Get size for mapping pairs failed for "
|
ntfs_log_error( "Get size for mapping pairs failed for "
|
||||||
"mft data attribute extent.\n" );
|
"mft data attribute extent.\n" );
|
||||||
goto undo_alloc;
|
goto undo_alloc;
|
||||||
@ -1079,11 +1138,13 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
/* Expand the attribute record if necessary. */
|
/* Expand the attribute record if necessary. */
|
||||||
old_alen = le32_to_cpu( a->length );
|
old_alen = le32_to_cpu( a->length );
|
||||||
if ( ntfs_attr_record_resize( m, a,
|
if ( ntfs_attr_record_resize( m, a,
|
||||||
mp_size + le16_to_cpu(a->mapping_pairs_offset))) {
|
mp_size + le16_to_cpu( a->mapping_pairs_offset ) ) )
|
||||||
|
{
|
||||||
ret = ntfs_mft_attr_extend( vol->mft_na );
|
ret = ntfs_mft_attr_extend( vol->mft_na );
|
||||||
if ( ret == STATUS_OK )
|
if ( ret == STATUS_OK )
|
||||||
goto ok;
|
goto ok;
|
||||||
if (ret == STATUS_ERROR) {
|
if ( ret == STATUS_ERROR )
|
||||||
|
{
|
||||||
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
|
ntfs_log_perror( "%s: ntfs_mft_attr_extend failed", __FUNCTION__ );
|
||||||
update_mp = TRUE;
|
update_mp = TRUE;
|
||||||
}
|
}
|
||||||
@ -1095,7 +1156,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
*/
|
*/
|
||||||
if ( ntfs_mapping_pairs_build( vol,
|
if ( ntfs_mapping_pairs_build( vol,
|
||||||
( u8* )a + le16_to_cpu( a->mapping_pairs_offset ), mp_size,
|
( u8* )a + le16_to_cpu( a->mapping_pairs_offset ), mp_size,
|
||||||
rl2, ll, NULL)) {
|
rl2, ll, NULL ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to build mapping pairs array of "
|
ntfs_log_error( "Failed to build mapping pairs array of "
|
||||||
"mft data attribute.\n" );
|
"mft data attribute.\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -1109,7 +1171,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
* @rl is the last (non-terminator) runlist element of mft data
|
* @rl is the last (non-terminator) runlist element of mft data
|
||||||
* attribute.
|
* attribute.
|
||||||
*/
|
*/
|
||||||
if (a->lowest_vcn) {
|
if ( a->lowest_vcn )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* We are not in the first attribute extent, switch to it, but
|
* We are not in the first attribute extent, switch to it, but
|
||||||
* first ensure the changes will make it to disk later.
|
* first ensure the changes will make it to disk later.
|
||||||
@ -1117,7 +1180,8 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
|||||||
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
if ( ntfs_attr_lookup( mft_na->type, mft_na->name,
|
if ( ntfs_attr_lookup( mft_na->type, mft_na->name,
|
||||||
mft_na->name_len, 0, 0, NULL, 0, ctx)) {
|
mft_na->name_len, 0, 0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find first attribute "
|
ntfs_log_error( "Failed to find first attribute "
|
||||||
"extent of mft data attribute.\n" );
|
"extent of mft data attribute.\n" );
|
||||||
goto restore_undo_alloc;
|
goto restore_undo_alloc;
|
||||||
@ -1139,7 +1203,8 @@ restore_undo_alloc:
|
|||||||
err = errno;
|
err = errno;
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx( ctx );
|
||||||
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||||
rl[1].vcn, NULL, 0, ctx)) {
|
rl[1].vcn, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find last attribute extent of "
|
ntfs_log_error( "Failed to find last attribute extent of "
|
||||||
"mft data attribute.%s\n", es );
|
"mft data attribute.%s\n", es );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
@ -1164,7 +1229,8 @@ undo_alloc:
|
|||||||
if ( ntfs_rl_truncate( &mft_na->rl, old_last_vcn ) )
|
if ( ntfs_rl_truncate( &mft_na->rl, old_last_vcn ) )
|
||||||
ntfs_log_error( "Failed to truncate mft data attribute "
|
ntfs_log_error( "Failed to truncate mft data attribute "
|
||||||
"runlist.%s\n", es );
|
"runlist.%s\n", es );
|
||||||
if (mp_rebuilt) {
|
if ( mp_rebuilt )
|
||||||
|
{
|
||||||
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
if ( ntfs_mapping_pairs_build( vol, ( u8* )a +
|
||||||
le16_to_cpu( a->mapping_pairs_offset ),
|
le16_to_cpu( a->mapping_pairs_offset ),
|
||||||
old_alen - le16_to_cpu( a->mapping_pairs_offset ),
|
old_alen - le16_to_cpu( a->mapping_pairs_offset ),
|
||||||
@ -1176,7 +1242,8 @@ undo_alloc:
|
|||||||
"record.%s\n", es );
|
"record.%s\n", es );
|
||||||
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
||||||
}
|
}
|
||||||
if (update_mp) {
|
if ( update_mp )
|
||||||
|
{
|
||||||
if ( ntfs_attr_update_mapping_pairs( vol->mft_na, 0 ) )
|
if ( ntfs_attr_update_mapping_pairs( vol->mft_na, 0 ) )
|
||||||
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
|
ntfs_log_perror( "%s: MP update failed", __FUNCTION__ );
|
||||||
}
|
}
|
||||||
@ -1213,7 +1280,8 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
|
|||||||
( long long )mft_na->allocated_size,
|
( long long )mft_na->allocated_size,
|
||||||
( long long )mft_na->data_size,
|
( long long )mft_na->data_size,
|
||||||
( long long )mft_na->initialized_size );
|
( long long )mft_na->initialized_size );
|
||||||
while (size > mft_na->allocated_size) {
|
while ( size > mft_na->allocated_size )
|
||||||
|
{
|
||||||
if ( ntfs_mft_data_extend_allocation( vol ) == STATUS_ERROR )
|
if ( ntfs_mft_data_extend_allocation( vol ) == STATUS_ERROR )
|
||||||
goto out;
|
goto out;
|
||||||
ntfs_log_debug( "Status of mft data after allocation extension: "
|
ntfs_log_debug( "Status of mft data after allocation extension: "
|
||||||
@ -1234,13 +1302,15 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
|
|||||||
* needed by ntfs_mft_record_format(). We will update the attribute
|
* needed by ntfs_mft_record_format(). We will update the attribute
|
||||||
* record itself in one fell swoop later on.
|
* record itself in one fell swoop later on.
|
||||||
*/
|
*/
|
||||||
while (size > mft_na->initialized_size) {
|
while ( size > mft_na->initialized_size )
|
||||||
|
{
|
||||||
s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
|
s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||||
mft_na->initialized_size += vol->mft_record_size;
|
mft_na->initialized_size += vol->mft_record_size;
|
||||||
if ( mft_na->initialized_size > mft_na->data_size )
|
if ( mft_na->initialized_size > mft_na->data_size )
|
||||||
mft_na->data_size = mft_na->initialized_size;
|
mft_na->data_size = mft_na->initialized_size;
|
||||||
ntfs_log_debug( "Initializing mft record 0x%llx.\n", ( long long )ll2 );
|
ntfs_log_debug( "Initializing mft record 0x%llx.\n", ( long long )ll2 );
|
||||||
if (ntfs_mft_record_format(vol, ll2) < 0) {
|
if ( ntfs_mft_record_format( vol, ll2 ) < 0 )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Failed to format mft record" );
|
ntfs_log_perror( "Failed to format mft record" );
|
||||||
goto undo_data_init;
|
goto undo_data_init;
|
||||||
}
|
}
|
||||||
@ -1252,7 +1322,8 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
|
|||||||
goto undo_data_init;
|
goto undo_data_init;
|
||||||
|
|
||||||
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||||
0, NULL, 0, ctx)) {
|
0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find first attribute extent of "
|
ntfs_log_error( "Failed to find first attribute extent of "
|
||||||
"mft data attribute.\n" );
|
"mft data attribute.\n" );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
@ -1304,7 +1375,8 @@ static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size)
|
|||||||
mft_na = vol->mft_na;
|
mft_na = vol->mft_na;
|
||||||
mftbmp_na = vol->mftbmp_na;
|
mftbmp_na = vol->mftbmp_na;
|
||||||
|
|
||||||
if (size > mft_na->allocated_size || size > mft_na->initialized_size) {
|
if ( size > mft_na->allocated_size || size > mft_na->initialized_size )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: unexpected $MFT sizes, see below", __FUNCTION__ );
|
ntfs_log_perror( "%s: unexpected $MFT sizes, see below", __FUNCTION__ );
|
||||||
ntfs_log_error( "$MFT: size=%lld allocated_size=%lld "
|
ntfs_log_error( "$MFT: size=%lld allocated_size=%lld "
|
||||||
@ -1325,7 +1397,8 @@ static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size)
|
|||||||
goto undo_data_init;
|
goto undo_data_init;
|
||||||
|
|
||||||
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
if ( ntfs_attr_lookup( mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||||
0, NULL, 0, ctx)) {
|
0, NULL, 0, ctx ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to find first attribute extent of "
|
ntfs_log_error( "Failed to find first attribute extent of "
|
||||||
"mft data attribute.\n" );
|
"mft data attribute.\n" );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
@ -1384,7 +1457,8 @@ static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
found_free_rec:
|
found_free_rec:
|
||||||
if (ntfs_bitmap_set_bit(mftbmp_na, bit)) {
|
if ( ntfs_bitmap_set_bit( mftbmp_na, bit ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to allocate bit in mft bitmap #2\n" );
|
ntfs_log_error( "Failed to allocate bit in mft bitmap #2\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -1403,12 +1477,14 @@ found_free_rec:
|
|||||||
if ( !m )
|
if ( !m )
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
|
|
||||||
if (ntfs_mft_record_read(vol, bit, m)) {
|
if ( ntfs_mft_record_read( vol, bit, m ) )
|
||||||
|
{
|
||||||
free( m );
|
free( m );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
}
|
}
|
||||||
/* Sanity check that the mft record is really not in use. */
|
/* Sanity check that the mft record is really not in use. */
|
||||||
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
|
if ( ntfs_is_file_record( m->magic ) && ( m->flags & MFT_RECORD_IN_USE ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Inode %lld is used but it wasn't marked in "
|
ntfs_log_error( "Inode %lld is used but it wasn't marked in "
|
||||||
"$MFT bitmap. Fixed.\n", ( long long )bit );
|
"$MFT bitmap. Fixed.\n", ( long long )bit );
|
||||||
free( m );
|
free( m );
|
||||||
@ -1417,7 +1493,8 @@ found_free_rec:
|
|||||||
|
|
||||||
seq_no = m->sequence_number;
|
seq_no = m->sequence_number;
|
||||||
usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) );
|
usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) );
|
||||||
if (ntfs_mft_record_layout(vol, bit, m)) {
|
if ( ntfs_mft_record_layout( vol, bit, m ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to re-format mft record.\n" );
|
ntfs_log_error( "Failed to re-format mft record.\n" );
|
||||||
free( m );
|
free( m );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
@ -1431,7 +1508,8 @@ found_free_rec:
|
|||||||
m->flags |= MFT_RECORD_IN_USE;
|
m->flags |= MFT_RECORD_IN_USE;
|
||||||
/* Now need to open an ntfs inode for the mft record. */
|
/* Now need to open an ntfs inode for the mft record. */
|
||||||
ni = ntfs_inode_allocate( vol );
|
ni = ntfs_inode_allocate( vol );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to allocate buffer for inode.\n" );
|
ntfs_log_error( "Failed to allocate buffer for inode.\n" );
|
||||||
free( m );
|
free( m );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
@ -1451,18 +1529,21 @@ found_free_rec:
|
|||||||
* Attach the extent inode to the base inode, reallocating
|
* Attach the extent inode to the base inode, reallocating
|
||||||
* memory if needed.
|
* memory if needed.
|
||||||
*/
|
*/
|
||||||
if (!(base_ni->nr_extents & 3)) {
|
if ( !( base_ni->nr_extents & 3 ) )
|
||||||
|
{
|
||||||
ntfs_inode **extent_nis;
|
ntfs_inode **extent_nis;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
||||||
extent_nis = ntfs_malloc( i );
|
extent_nis = ntfs_malloc( i );
|
||||||
if (!extent_nis) {
|
if ( !extent_nis )
|
||||||
|
{
|
||||||
free( m );
|
free( m );
|
||||||
free( ni );
|
free( ni );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
}
|
}
|
||||||
if (base_ni->nr_extents) {
|
if ( base_ni->nr_extents )
|
||||||
|
{
|
||||||
memcpy( extent_nis, base_ni->extent_nis,
|
memcpy( extent_nis, base_ni->extent_nis,
|
||||||
i - 4 * sizeof( ntfs_inode * ) );
|
i - 4 * sizeof( ntfs_inode * ) );
|
||||||
free( base_ni->extent_nis );
|
free( base_ni->extent_nis );
|
||||||
@ -1599,12 +1680,14 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||||||
( long long )base_ni->mft_no );
|
( long long )base_ni->mft_no );
|
||||||
else
|
else
|
||||||
ntfs_log_enter( "Entering (allocating a base mft record)\n" );
|
ntfs_log_enter( "Entering (allocating a base mft record)\n" );
|
||||||
if (!vol || !vol->mft_na || !vol->mftbmp_na) {
|
if ( !vol || !vol->mft_na || !vol->mftbmp_na )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntfs_is_mft(base_ni)) {
|
if ( ntfs_is_mft( base_ni ) )
|
||||||
|
{
|
||||||
ni = ntfs_mft_rec_alloc( vol );
|
ni = ntfs_mft_rec_alloc( vol );
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1613,7 +1696,8 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||||||
mftbmp_na = vol->mftbmp_na;
|
mftbmp_na = vol->mftbmp_na;
|
||||||
retry:
|
retry:
|
||||||
bit = ntfs_mft_bitmap_find_free_rec( vol, base_ni );
|
bit = ntfs_mft_bitmap_find_free_rec( vol, base_ni );
|
||||||
if (bit >= 0) {
|
if ( bit >= 0 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "found free record (#1) at %lld\n",
|
ntfs_log_debug( "found free record (#1) at %lld\n",
|
||||||
( long long )bit );
|
( long long )bit );
|
||||||
goto found_free_rec;
|
goto found_free_rec;
|
||||||
@ -1630,7 +1714,8 @@ retry:
|
|||||||
*/
|
*/
|
||||||
ll = mft_na->initialized_size >> vol->mft_record_size_bits;
|
ll = mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||||
if ( mftbmp_na->initialized_size << 3 > ll &&
|
if ( mftbmp_na->initialized_size << 3 > ll &&
|
||||||
mftbmp_na->initialized_size > RESERVED_MFT_RECORDS / 8) {
|
mftbmp_na->initialized_size > RESERVED_MFT_RECORDS / 8 )
|
||||||
|
{
|
||||||
bit = ll;
|
bit = ll;
|
||||||
if ( bit < RESERVED_MFT_RECORDS )
|
if ( bit < RESERVED_MFT_RECORDS )
|
||||||
bit = RESERVED_MFT_RECORDS;
|
bit = RESERVED_MFT_RECORDS;
|
||||||
@ -1648,13 +1733,15 @@ retry:
|
|||||||
( long long )mftbmp_na->allocated_size,
|
( long long )mftbmp_na->allocated_size,
|
||||||
( long long )mftbmp_na->data_size,
|
( long long )mftbmp_na->data_size,
|
||||||
( long long )mftbmp_na->initialized_size );
|
( long long )mftbmp_na->initialized_size );
|
||||||
if (mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size) {
|
if ( mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size )
|
||||||
|
{
|
||||||
|
|
||||||
int ret = ntfs_mft_bitmap_extend_allocation( vol );
|
int ret = ntfs_mft_bitmap_extend_allocation( vol );
|
||||||
|
|
||||||
if ( ret == STATUS_ERROR )
|
if ( ret == STATUS_ERROR )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
if (ret == STATUS_KEEP_SEARCHING) {
|
if ( ret == STATUS_KEEP_SEARCHING )
|
||||||
|
{
|
||||||
ret = ntfs_mft_bitmap_extend_allocation( vol );
|
ret = ntfs_mft_bitmap_extend_allocation( vol );
|
||||||
if ( ret != STATUS_OK )
|
if ( ret != STATUS_OK )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -1684,7 +1771,8 @@ retry:
|
|||||||
ntfs_log_debug( "found free record (#3) at %lld\n", ( long long )bit );
|
ntfs_log_debug( "found free record (#3) at %lld\n", ( long long )bit );
|
||||||
found_free_rec:
|
found_free_rec:
|
||||||
/* @bit is the found free mft record, allocate it in the mft bitmap. */
|
/* @bit is the found free mft record, allocate it in the mft bitmap. */
|
||||||
if (ntfs_bitmap_set_bit(mftbmp_na, bit)) {
|
if ( ntfs_bitmap_set_bit( mftbmp_na, bit ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to allocate bit in mft bitmap.\n" );
|
ntfs_log_error( "Failed to allocate bit in mft bitmap.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -1705,12 +1793,14 @@ found_free_rec:
|
|||||||
if ( !m )
|
if ( !m )
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
|
|
||||||
if (ntfs_mft_record_read(vol, bit, m)) {
|
if ( ntfs_mft_record_read( vol, bit, m ) )
|
||||||
|
{
|
||||||
free( m );
|
free( m );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
}
|
}
|
||||||
/* Sanity check that the mft record is really not in use. */
|
/* Sanity check that the mft record is really not in use. */
|
||||||
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
|
if ( ntfs_is_file_record( m->magic ) && ( m->flags & MFT_RECORD_IN_USE ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Inode %lld is used but it wasn't marked in "
|
ntfs_log_error( "Inode %lld is used but it wasn't marked in "
|
||||||
"$MFT bitmap. Fixed.\n", ( long long )bit );
|
"$MFT bitmap. Fixed.\n", ( long long )bit );
|
||||||
free( m );
|
free( m );
|
||||||
@ -1718,7 +1808,8 @@ found_free_rec:
|
|||||||
}
|
}
|
||||||
seq_no = m->sequence_number;
|
seq_no = m->sequence_number;
|
||||||
usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) );
|
usn = *( le16* )( ( u8* )m + le16_to_cpu( m->usa_ofs ) );
|
||||||
if (ntfs_mft_record_layout(vol, bit, m)) {
|
if ( ntfs_mft_record_layout( vol, bit, m ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to re-format mft record.\n" );
|
ntfs_log_error( "Failed to re-format mft record.\n" );
|
||||||
free( m );
|
free( m );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
@ -1732,7 +1823,8 @@ found_free_rec:
|
|||||||
m->flags |= MFT_RECORD_IN_USE;
|
m->flags |= MFT_RECORD_IN_USE;
|
||||||
/* Now need to open an ntfs inode for the mft record. */
|
/* Now need to open an ntfs inode for the mft record. */
|
||||||
ni = ntfs_inode_allocate( vol );
|
ni = ntfs_inode_allocate( vol );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to allocate buffer for inode.\n" );
|
ntfs_log_error( "Failed to allocate buffer for inode.\n" );
|
||||||
free( m );
|
free( m );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
@ -1744,7 +1836,8 @@ found_free_rec:
|
|||||||
* extent inode and attach it to the base inode. Also, set the base
|
* extent inode and attach it to the base inode. Also, set the base
|
||||||
* mft record reference in the extent inode.
|
* mft record reference in the extent inode.
|
||||||
*/
|
*/
|
||||||
if (base_ni) {
|
if ( base_ni )
|
||||||
|
{
|
||||||
ni->nr_extents = -1;
|
ni->nr_extents = -1;
|
||||||
ni->base_ni = base_ni;
|
ni->base_ni = base_ni;
|
||||||
m->base_mft_record = MK_LE_MREF( base_ni->mft_no,
|
m->base_mft_record = MK_LE_MREF( base_ni->mft_no,
|
||||||
@ -1753,18 +1846,21 @@ found_free_rec:
|
|||||||
* Attach the extent inode to the base inode, reallocating
|
* Attach the extent inode to the base inode, reallocating
|
||||||
* memory if needed.
|
* memory if needed.
|
||||||
*/
|
*/
|
||||||
if (!(base_ni->nr_extents & 3)) {
|
if ( !( base_ni->nr_extents & 3 ) )
|
||||||
|
{
|
||||||
ntfs_inode **extent_nis;
|
ntfs_inode **extent_nis;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
i = ( base_ni->nr_extents + 4 ) * sizeof( ntfs_inode * );
|
||||||
extent_nis = ntfs_malloc( i );
|
extent_nis = ntfs_malloc( i );
|
||||||
if (!extent_nis) {
|
if ( !extent_nis )
|
||||||
|
{
|
||||||
free( m );
|
free( m );
|
||||||
free( ni );
|
free( ni );
|
||||||
goto undo_mftbmp_alloc;
|
goto undo_mftbmp_alloc;
|
||||||
}
|
}
|
||||||
if (base_ni->nr_extents) {
|
if ( base_ni->nr_extents )
|
||||||
|
{
|
||||||
memcpy( extent_nis, base_ni->extent_nis,
|
memcpy( extent_nis, base_ni->extent_nis,
|
||||||
i - 4 * sizeof( ntfs_inode * ) );
|
i - 4 * sizeof( ntfs_inode * ) );
|
||||||
free( base_ni->extent_nis );
|
free( base_ni->extent_nis );
|
||||||
@ -1824,7 +1920,8 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
|
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
|
||||||
|
|
||||||
if (!vol || !vol->mftbmp_na || !ni) {
|
if ( !vol || !vol->mftbmp_na || !ni )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1846,13 +1943,15 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
|
|||||||
|
|
||||||
/* Set the inode dirty and write it out. */
|
/* Set the inode dirty and write it out. */
|
||||||
ntfs_inode_mark_dirty( ni );
|
ntfs_inode_mark_dirty( ni );
|
||||||
if (ntfs_inode_sync(ni)) {
|
if ( ntfs_inode_sync( ni ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto sync_rollback;
|
goto sync_rollback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
|
/* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
|
||||||
if (ntfs_bitmap_clear_bit(vol->mftbmp_na, mft_no)) {
|
if ( ntfs_bitmap_clear_bit( vol->mftbmp_na, mft_no ) )
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
// FIXME: If ntfs_bitmap_clear_run() guarantees rollback on
|
// FIXME: If ntfs_bitmap_clear_run() guarantees rollback on
|
||||||
// error, this could be changed to goto sync_rollback;
|
// error, this could be changed to goto sync_rollback;
|
||||||
@ -1861,9 +1960,11 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
|
|||||||
|
|
||||||
/* Throw away the now freed inode. */
|
/* Throw away the now freed inode. */
|
||||||
#if CACHE_NIDATA_SIZE
|
#if CACHE_NIDATA_SIZE
|
||||||
if (!ntfs_inode_real_close(ni)) {
|
if ( !ntfs_inode_real_close( ni ) )
|
||||||
|
{
|
||||||
#else
|
#else
|
||||||
if (!ntfs_inode_close(ni)) {
|
if ( !ntfs_inode_close( ni ) )
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
vol->free_mft_records++;
|
vol->free_mft_records++;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1894,7 +1995,8 @@ int ntfs_mft_usn_dec(MFT_RECORD *mrec)
|
|||||||
u16 usn;
|
u16 usn;
|
||||||
le16 *usnp;
|
le16 *usnp;
|
||||||
|
|
||||||
if (!mrec) {
|
if ( !mrec )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
/* Size and alignment checks. */
|
/* Size and alignment checks. */
|
||||||
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
||||||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
||||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: magic: 0x%08x size: %d usa_ofs: %d "
|
ntfs_log_perror( "%s: magic: 0x%08x size: %d usa_ofs: %d "
|
||||||
"usa_count: %d", __FUNCTION__, *( le32 * )b,
|
"usa_count: %d", __FUNCTION__, *( le32 * )b,
|
||||||
@ -85,8 +86,10 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
/*
|
/*
|
||||||
* Check for incomplete multi sector transfer(s).
|
* Check for incomplete multi sector transfer(s).
|
||||||
*/
|
*/
|
||||||
while (usa_count--) {
|
while ( usa_count-- )
|
||||||
if (*data_pos != usn) {
|
{
|
||||||
|
if ( *data_pos != usn )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Incomplete multi sector transfer detected! )-:
|
* Incomplete multi sector transfer detected! )-:
|
||||||
* Set the magic to "BAAD" and return failure.
|
* Set the magic to "BAAD" and return failure.
|
||||||
@ -106,7 +109,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
usa_count = le16_to_cpu( b->usa_count ) - 1;
|
usa_count = le16_to_cpu( b->usa_count ) - 1;
|
||||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while (usa_count--) {
|
while ( usa_count-- )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Increment position in usa and restore original data from
|
* Increment position in usa and restore original data from
|
||||||
* the usa into the data buffer.
|
* the usa into the data buffer.
|
||||||
@ -147,7 +151,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
|
|
||||||
/* Sanity check + only fixup if it makes sense. */
|
/* Sanity check + only fixup if it makes sense. */
|
||||||
if ( !b || ntfs_is_baad_record( b->magic ) ||
|
if ( !b || ntfs_is_baad_record( b->magic ) ||
|
||||||
ntfs_is_hole_record(b->magic)) {
|
ntfs_is_hole_record( b->magic ) )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: bad argument", __FUNCTION__ );
|
ntfs_log_perror( "%s: bad argument", __FUNCTION__ );
|
||||||
return -1;
|
return -1;
|
||||||
@ -159,7 +164,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
/* Size and alignment checks. */
|
/* Size and alignment checks. */
|
||||||
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
||||||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
||||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
ntfs_log_perror( "%s", __FUNCTION__ );
|
||||||
return -1;
|
return -1;
|
||||||
@ -178,7 +184,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
/* Position in data of first u16 that needs fixing up. */
|
/* Position in data of first u16 that needs fixing up. */
|
||||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while (usa_count--) {
|
while ( usa_count-- )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Increment the position in the usa and save the
|
* Increment the position in the usa and save the
|
||||||
* original data from the data buffer into the usa.
|
* original data from the data buffer into the usa.
|
||||||
@ -217,7 +224,8 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
|||||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
||||||
|
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while (usa_count--) {
|
while ( usa_count-- )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Increment position in usa and restore original data from
|
* Increment position in usa and restore original data from
|
||||||
* the usa into the data buffer.
|
* the usa into the data buffer.
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
// NTFS device driver devoptab
|
// NTFS device driver devoptab
|
||||||
static const devoptab_t devops_ntfs = {
|
static const devoptab_t devops_ntfs =
|
||||||
|
{
|
||||||
NULL, /* Device name */
|
NULL, /* Device name */
|
||||||
sizeof ( ntfs_file_state ),
|
sizeof ( ntfs_file_state ),
|
||||||
ntfs_open_r,
|
ntfs_open_r,
|
||||||
@ -72,7 +73,8 @@ void ntfsInit (void)
|
|||||||
static bool isInit = false;
|
static bool isInit = false;
|
||||||
|
|
||||||
// Initialise ntfs-3g (if not already done so)
|
// Initialise ntfs-3g (if not already done so)
|
||||||
if (!isInit) {
|
if ( !isInit )
|
||||||
|
{
|
||||||
isInit = true;
|
isInit = true;
|
||||||
|
|
||||||
// Set the log handler
|
// Set the log handler
|
||||||
@ -98,7 +100,8 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
sec_t part_lba = 0;
|
sec_t part_lba = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
u8 buffer[512];
|
u8 buffer[512];
|
||||||
MASTER_BOOT_RECORD mbr;
|
MASTER_BOOT_RECORD mbr;
|
||||||
EXTENDED_BOOT_RECORD ebr;
|
EXTENDED_BOOT_RECORD ebr;
|
||||||
@ -106,7 +109,8 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
} sector;
|
} sector;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!interface) {
|
if ( !interface )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -117,27 +121,32 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Start the device and check that it is inserted
|
// Start the device and check that it is inserted
|
||||||
if (!interface->startup()) {
|
if ( !interface->startup() )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!interface->isInserted()) {
|
if ( !interface->isInserted() )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the first sector on the device
|
// Read the first sector on the device
|
||||||
if (!interface->readSectors(0, 1, §or.buffer)) {
|
if ( !interface->readSectors( 0, 1, §or.buffer ) )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is the devices master boot record
|
// If this is the devices master boot record
|
||||||
if (sector.mbr.signature == MBR_SIGNATURE) {
|
if ( sector.mbr.signature == MBR_SIGNATURE )
|
||||||
|
{
|
||||||
memcpy( &mbr, §or, sizeof( MASTER_BOOT_RECORD ) );
|
memcpy( &mbr, §or, sizeof( MASTER_BOOT_RECORD ) );
|
||||||
ntfs_log_debug( "Valid Master Boot Record found\n" );
|
ntfs_log_debug( "Valid Master Boot Record found\n" );
|
||||||
|
|
||||||
// Search the partition table for all NTFS partitions (max. 4 primary partitions)
|
// Search the partition table for all NTFS partitions (max. 4 primary partitions)
|
||||||
for (i = 0; i < 4; i++) {
|
for ( i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
partition = &mbr.partitions[i];
|
partition = &mbr.partitions[i];
|
||||||
part_lba = le32_to_cpu( mbr.partitions[i].lba_start );
|
part_lba = le32_to_cpu( mbr.partitions[i].lba_start );
|
||||||
|
|
||||||
@ -146,25 +155,32 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
part_lba, partition->type );
|
part_lba, partition->type );
|
||||||
|
|
||||||
// Figure out what type of partition this is
|
// Figure out what type of partition this is
|
||||||
switch (partition->type) {
|
switch ( partition->type )
|
||||||
|
{
|
||||||
|
|
||||||
// Ignore empty partitions
|
// Ignore empty partitions
|
||||||
case PARTITION_TYPE_EMPTY:
|
case PARTITION_TYPE_EMPTY:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// NTFS partition
|
// NTFS partition
|
||||||
case PARTITION_TYPE_NTFS: {
|
case PARTITION_TYPE_NTFS:
|
||||||
|
{
|
||||||
ntfs_log_debug( "Partition %i: Claims to be NTFS\n", i + 1 );
|
ntfs_log_debug( "Partition %i: Claims to be NTFS\n", i + 1 );
|
||||||
|
|
||||||
// Read and validate the NTFS partition
|
// Read and validate the NTFS partition
|
||||||
if (interface->readSectors(part_lba, 1, §or)) {
|
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
{
|
||||||
|
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
||||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||||
|
{
|
||||||
partition_starts[partition_count] = part_lba;
|
partition_starts[partition_count] = part_lba;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_debug( "Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1 );
|
ntfs_log_debug( "Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,17 +191,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
|
|
||||||
// DOS 3.3+ or Windows 95 extended partition
|
// DOS 3.3+ or Windows 95 extended partition
|
||||||
case PARTITION_TYPE_DOS33_EXTENDED:
|
case PARTITION_TYPE_DOS33_EXTENDED:
|
||||||
case PARTITION_TYPE_WIN95_EXTENDED: {
|
case PARTITION_TYPE_WIN95_EXTENDED:
|
||||||
|
{
|
||||||
ntfs_log_debug( "Partition %i: Claims to be Extended\n", i + 1 );
|
ntfs_log_debug( "Partition %i: Claims to be Extended\n", i + 1 );
|
||||||
|
|
||||||
// Walk the extended partition chain, finding all NTFS partitions within it
|
// Walk the extended partition chain, finding all NTFS partitions within it
|
||||||
sec_t ebr_lba = part_lba;
|
sec_t ebr_lba = part_lba;
|
||||||
sec_t next_erb_lba = 0;
|
sec_t next_erb_lba = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
|
|
||||||
// Read and validate the extended boot record
|
// Read and validate the extended boot record
|
||||||
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or)) {
|
if ( interface->readSectors( ebr_lba + next_erb_lba, 1, §or ) )
|
||||||
if (sector.ebr.signature == EBR_SIGNATURE) {
|
{
|
||||||
|
if ( sector.ebr.signature == EBR_SIGNATURE )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
ntfs_log_debug( "Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
||||||
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||||
sector.ebr.partition.type );
|
sector.ebr.partition.type );
|
||||||
@ -196,42 +216,54 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
next_erb_lba = le32_to_cpu( sector.ebr.next_ebr.lba_start );
|
next_erb_lba = le32_to_cpu( sector.ebr.next_ebr.lba_start );
|
||||||
|
|
||||||
// Check if this partition has a valid NTFS boot record
|
// Check if this partition has a valid NTFS boot record
|
||||||
if (interface->readSectors(part_lba, 1, §or)) {
|
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
{
|
||||||
|
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba );
|
ntfs_log_debug( "Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba );
|
||||||
if(sector.ebr.partition.type != PARTITION_TYPE_NTFS) {
|
if ( sector.ebr.partition.type != PARTITION_TYPE_NTFS )
|
||||||
|
{
|
||||||
ntfs_log_warning( "Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS );
|
ntfs_log_warning( "Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS );
|
||||||
}
|
}
|
||||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||||
|
{
|
||||||
partition_starts[partition_count] = part_lba;
|
partition_starts[partition_count] = part_lba;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
next_erb_lba = 0;
|
next_erb_lba = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (next_erb_lba);
|
}
|
||||||
|
while ( next_erb_lba );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown or unsupported partition type
|
// Unknown or unsupported partition type
|
||||||
default: {
|
default:
|
||||||
|
{
|
||||||
|
|
||||||
// Check if this partition has a valid NTFS boot record anyway,
|
// Check if this partition has a valid NTFS boot record anyway,
|
||||||
// it might be misrepresented due to a lazy partition editor
|
// it might be misrepresented due to a lazy partition editor
|
||||||
if (interface->readSectors(part_lba, 1, §or)) {
|
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
{
|
||||||
|
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
||||||
if(partition->type != PARTITION_TYPE_NTFS) {
|
if ( partition->type != PARTITION_TYPE_NTFS )
|
||||||
|
{
|
||||||
ntfs_log_warning( "Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS );
|
ntfs_log_warning( "Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS );
|
||||||
}
|
}
|
||||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||||
|
{
|
||||||
partition_starts[partition_count] = part_lba;
|
partition_starts[partition_count] = part_lba;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
@ -247,15 +279,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Else it is assumed this device has no master boot record
|
// Else it is assumed this device has no master boot record
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_debug( "No Master Boot Record was found!\n" );
|
ntfs_log_debug( "No Master Boot Record was found!\n" );
|
||||||
|
|
||||||
// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
|
// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
|
||||||
for (i = 0; i < 64; i++) {
|
for ( i = 0; i < 64; i++ )
|
||||||
if (interface->readSectors(i, 1, §or)) {
|
{
|
||||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
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 );
|
ntfs_log_debug( "Valid NTFS boot sector found at sector %d!\n", i );
|
||||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||||
|
{
|
||||||
partition_starts[partition_count] = i;
|
partition_starts[partition_count] = i;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
@ -269,9 +307,11 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|||||||
/*interface->shutdown();*/
|
/*interface->shutdown();*/
|
||||||
|
|
||||||
// Return the found partitions (if any)
|
// Return the found partitions (if any)
|
||||||
if (partition_count > 0) {
|
if ( partition_count > 0 )
|
||||||
|
{
|
||||||
*partitions = ( sec_t* )ntfs_alloc( sizeof( sec_t ) * partition_count );
|
*partitions = ( sec_t* )ntfs_alloc( sizeof( sec_t ) * partition_count );
|
||||||
if (*partitions) {
|
if ( *partitions )
|
||||||
|
{
|
||||||
memcpy( *partitions, &partition_starts, sizeof( sec_t ) * partition_count );
|
memcpy( *partitions, &partition_starts, sizeof( sec_t ) * partition_count );
|
||||||
return partition_count;
|
return partition_count;
|
||||||
}
|
}
|
||||||
@ -295,25 +335,33 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
|||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Find and mount all NTFS partitions on all known devices
|
// Find and mount all NTFS partitions on all known devices
|
||||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
for ( i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++ )
|
||||||
|
{
|
||||||
disc = &discs[i];
|
disc = &discs[i];
|
||||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
||||||
if (partition_count > 0 && partitions) {
|
if ( partition_count > 0 && partitions )
|
||||||
for (j = 0, k = 0; j < partition_count; j++) {
|
{
|
||||||
|
for ( j = 0, k = 0; j < partition_count; j++ )
|
||||||
|
{
|
||||||
|
|
||||||
// Find the next unused mount name
|
// Find the next unused mount name
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
||||||
if (k >= NTFS_MAX_MOUNTS) {
|
if ( k >= NTFS_MAX_MOUNTS )
|
||||||
|
{
|
||||||
ntfs_free( partitions );
|
ntfs_free( partitions );
|
||||||
errno = EADDRNOTAVAIL;
|
errno = EADDRNOTAVAIL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} while (ntfsGetDevice(name, false));
|
}
|
||||||
|
while ( ntfsGetDevice( name, false ) );
|
||||||
|
|
||||||
// Mount the partition
|
// Mount the partition
|
||||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
if ( mount_count < NTFS_MAX_MOUNTS )
|
||||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
{
|
||||||
|
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
||||||
|
{
|
||||||
strcpy( mount_points[mount_count].name, name );
|
strcpy( mount_points[mount_count].name, name );
|
||||||
mount_points[mount_count].interface = disc->interface;
|
mount_points[mount_count].interface = disc->interface;
|
||||||
mount_points[mount_count].startSector = partitions[j];
|
mount_points[mount_count].startSector = partitions[j];
|
||||||
@ -327,9 +375,11 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the mounts (if any)
|
// Return the mounts (if any)
|
||||||
if (mount_count > 0 && mounts) {
|
if ( mount_count > 0 && mounts )
|
||||||
|
{
|
||||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
||||||
if (*mounts) {
|
if ( *mounts )
|
||||||
|
{
|
||||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
||||||
return mount_count;
|
return mount_count;
|
||||||
}
|
}
|
||||||
@ -350,7 +400,8 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
|||||||
int i, j, k;
|
int i, j, k;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!interface) {
|
if ( !interface )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -359,26 +410,35 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
|||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Find the specified device then find and mount all NTFS partitions on it
|
// Find the specified device then find and mount all NTFS partitions on it
|
||||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
for ( i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++ )
|
||||||
if (discs[i].interface == interface) {
|
{
|
||||||
|
if ( discs[i].interface == interface )
|
||||||
|
{
|
||||||
disc = &discs[i];
|
disc = &discs[i];
|
||||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
||||||
if (partition_count > 0 && partitions) {
|
if ( partition_count > 0 && partitions )
|
||||||
for (j = 0, k = 0; j < partition_count; j++) {
|
{
|
||||||
|
for ( j = 0, k = 0; j < partition_count; j++ )
|
||||||
|
{
|
||||||
|
|
||||||
// Find the next unused mount name
|
// Find the next unused mount name
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
||||||
if (k >= NTFS_MAX_MOUNTS) {
|
if ( k >= NTFS_MAX_MOUNTS )
|
||||||
|
{
|
||||||
ntfs_free( partitions );
|
ntfs_free( partitions );
|
||||||
errno = EADDRNOTAVAIL;
|
errno = EADDRNOTAVAIL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} while (ntfsGetDevice(name, false));
|
}
|
||||||
|
while ( ntfsGetDevice( name, false ) );
|
||||||
|
|
||||||
// Mount the partition
|
// Mount the partition
|
||||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
if ( mount_count < NTFS_MAX_MOUNTS )
|
||||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
{
|
||||||
|
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
||||||
|
{
|
||||||
strcpy( mount_points[mount_count].name, name );
|
strcpy( mount_points[mount_count].name, name );
|
||||||
mount_points[mount_count].interface = disc->interface;
|
mount_points[mount_count].interface = disc->interface;
|
||||||
mount_points[mount_count].startSector = partitions[j];
|
mount_points[mount_count].startSector = partitions[j];
|
||||||
@ -394,15 +454,18 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we couldn't find the device then return with error status
|
// If we couldn't find the device then return with error status
|
||||||
if (!disc) {
|
if ( !disc )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the mounts (if any)
|
// Return the mounts (if any)
|
||||||
if (mount_count > 0 && mounts) {
|
if ( mount_count > 0 && mounts )
|
||||||
|
{
|
||||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
||||||
if (*mounts) {
|
if ( *mounts )
|
||||||
|
{
|
||||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
||||||
return mount_count;
|
return mount_count;
|
||||||
}
|
}
|
||||||
@ -417,7 +480,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
|||||||
gekko_fd *fd = NULL;
|
gekko_fd *fd = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!name || !interface) {
|
if ( !name || !interface )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -426,20 +490,23 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
|||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Check that the requested mount name is free
|
// Check that the requested mount name is free
|
||||||
if (ntfsGetDevice(name, false)) {
|
if ( ntfsGetDevice( name, false ) )
|
||||||
|
{
|
||||||
errno = EADDRINUSE;
|
errno = EADDRINUSE;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we can at least read from this device
|
// Check that we can at least read from this device
|
||||||
if (!(interface->features & FEATURE_MEDIUM_CANREAD)) {
|
if ( !( interface->features & FEATURE_MEDIUM_CANREAD ) )
|
||||||
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the volume descriptor
|
// Allocate the volume descriptor
|
||||||
vd = ( ntfs_vd* )ntfs_alloc( sizeof( ntfs_vd ) );
|
vd = ( ntfs_vd* )ntfs_alloc( sizeof( ntfs_vd ) );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -457,7 +524,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
|||||||
|
|
||||||
// Allocate the device driver descriptor
|
// Allocate the device driver descriptor
|
||||||
fd = ( gekko_fd* )ntfs_alloc( sizeof( gekko_fd ) );
|
fd = ( gekko_fd* )ntfs_alloc( sizeof( gekko_fd ) );
|
||||||
if (!fd) {
|
if ( !fd )
|
||||||
|
{
|
||||||
ntfs_free( vd );
|
ntfs_free( vd );
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return false;
|
return false;
|
||||||
@ -473,7 +541,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
|||||||
|
|
||||||
// Allocate the device driver
|
// Allocate the device driver
|
||||||
vd->dev = ntfs_device_alloc( name, 0, &ntfs_device_gekko_io_ops, fd );
|
vd->dev = ntfs_device_alloc( name, 0, &ntfs_device_gekko_io_ops, fd );
|
||||||
if (!vd->dev) {
|
if ( !vd->dev )
|
||||||
|
{
|
||||||
ntfs_free( fd );
|
ntfs_free( fd );
|
||||||
ntfs_free( vd );
|
ntfs_free( vd );
|
||||||
return false;
|
return false;
|
||||||
@ -499,8 +568,10 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
|||||||
|
|
||||||
// Mount the device
|
// Mount the device
|
||||||
vd->vol = ntfs_device_mount( vd->dev, vd->flags );
|
vd->vol = ntfs_device_mount( vd->dev, vd->flags );
|
||||||
if (!vd->vol) {
|
if ( !vd->vol )
|
||||||
switch(ntfs_volume_error(errno)) {
|
{
|
||||||
|
switch ( ntfs_volume_error( errno ) )
|
||||||
|
{
|
||||||
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
||||||
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
||||||
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
||||||
@ -513,14 +584,16 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the volume descriptor
|
// Initialise the volume descriptor
|
||||||
if (ntfsInitVolume(vd)) {
|
if ( ntfsInitVolume( vd ) )
|
||||||
|
{
|
||||||
ntfs_umount( vd->vol, true );
|
ntfs_umount( vd->vol, true );
|
||||||
ntfs_free( vd );
|
ntfs_free( vd );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the device to the devoptab table
|
// Add the device to the devoptab table
|
||||||
if (ntfsAddDevice(name, vd)) {
|
if ( ntfsAddDevice( name, vd ) )
|
||||||
|
{
|
||||||
ntfsDeinitVolume( vd );
|
ntfsDeinitVolume( vd );
|
||||||
ntfs_umount( vd->vol, true );
|
ntfs_umount( vd->vol, true );
|
||||||
ntfs_free( vd );
|
ntfs_free( vd );
|
||||||
@ -562,14 +635,16 @@ const char *ntfsGetVolumeName (const char *name)
|
|||||||
//char *volumeName = NULL;
|
//char *volumeName = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!name) {
|
if ( !name )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the devices volume descriptor
|
// Get the devices volume descriptor
|
||||||
vd = ntfsGetVolume( name );
|
vd = ntfsGetVolume( name );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -642,14 +717,16 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
|||||||
int ulabel_len;
|
int ulabel_len;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!name) {
|
if ( !name )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the devices volume descriptor
|
// Get the devices volume descriptor
|
||||||
vd = ntfsGetVolume( name );
|
vd = ntfsGetVolume( name );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -659,7 +736,8 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
|||||||
|
|
||||||
// Convert the new volume name to unicode
|
// Convert the new volume name to unicode
|
||||||
ulabel_len = ntfsLocalToUnicode( volumeName, &ulabel ) * sizeof( ntfschar );
|
ulabel_len = ntfsLocalToUnicode( volumeName, &ulabel ) * sizeof( ntfschar );
|
||||||
if (ulabel_len < 0) {
|
if ( ulabel_len < 0 )
|
||||||
|
{
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return false;
|
return false;
|
||||||
@ -667,26 +745,32 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
|||||||
|
|
||||||
// Check if the volume name attribute exists
|
// Check if the volume name attribute exists
|
||||||
na = ntfs_attr_open( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0 );
|
na = ntfs_attr_open( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
|
|
||||||
// It does, resize it to match the length of the new volume name
|
// It does, resize it to match the length of the new volume name
|
||||||
if (ntfs_attr_truncate(na, ulabel_len)) {
|
if ( ntfs_attr_truncate( na, ulabel_len ) )
|
||||||
|
{
|
||||||
ntfs_free( ulabel );
|
ntfs_free( ulabel );
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the new volume name
|
// Write the new volume name
|
||||||
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
|
if ( ntfs_attr_pwrite( na, 0, ulabel_len, ulabel ) != ulabel_len )
|
||||||
|
{
|
||||||
ntfs_free( ulabel );
|
ntfs_free( ulabel );
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
// It doesn't, create it now
|
// It doesn't, create it now
|
||||||
if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) {
|
if ( ntfs_attr_add( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, ( u8* )ulabel, ulabel_len ) )
|
||||||
|
{
|
||||||
ntfs_free( ulabel );
|
ntfs_free( ulabel );
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
return false;
|
return false;
|
||||||
@ -702,7 +786,8 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
|||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
|
|
||||||
// Sync the volume node
|
// Sync the volume node
|
||||||
if (ntfs_inode_sync(vd->vol->vol_ni)) {
|
if ( ntfs_inode_sync( vd->vol->vol_ni ) )
|
||||||
|
{
|
||||||
ntfs_free( ulabel );
|
ntfs_free( ulabel );
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
return false;
|
return false;
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
#define _LIBNTFS_H
|
#define _LIBNTFS_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gctypes.h>
|
#include <gctypes.h>
|
||||||
@ -54,7 +55,8 @@ extern "C" {
|
|||||||
/**
|
/**
|
||||||
* ntfs_md - NTFS mount descriptor
|
* ntfs_md - NTFS mount descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_md {
|
typedef struct _ntfs_md
|
||||||
|
{
|
||||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||||
sec_t startSector; /* Local block address to first sector of partition */
|
sec_t startSector; /* Local block address to first sector of partition */
|
||||||
|
@ -54,7 +54,8 @@ void ntfsCloseDir (ntfs_dir_state *dir)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Free the directory entries (if any)
|
// Free the directory entries (if any)
|
||||||
while (dir->first) {
|
while ( dir->first )
|
||||||
|
{
|
||||||
ntfs_dir_entry *next = dir->first->next;
|
ntfs_dir_entry *next = dir->first->next;
|
||||||
ntfs_free( dir->first->name );
|
ntfs_free( dir->first->name );
|
||||||
ntfs_free( dir->first );
|
ntfs_free( dir->first );
|
||||||
@ -86,7 +87,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( path );
|
vd = ntfsGetVolume( path );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -103,7 +105,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
|||||||
|
|
||||||
// Find the entry
|
// Find the entry
|
||||||
ni = ntfsOpenEntry( vd, path );
|
ni = ntfsOpenEntry( vd, path );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
return -1;
|
return -1;
|
||||||
@ -131,7 +134,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( existing );
|
vd = ntfsGetVolume( existing );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -141,7 +145,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
|||||||
|
|
||||||
// Create a symbolic link between the two paths
|
// Create a symbolic link between the two paths
|
||||||
ni = ntfsCreate( vd, existing, S_IFLNK, newLink );
|
ni = ntfsCreate( vd, existing, S_IFLNK, newLink );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
@ -177,7 +182,8 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( name );
|
vd = ntfsGetVolume( name );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -187,14 +193,16 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
|||||||
|
|
||||||
// Find the directory
|
// Find the directory
|
||||||
ni = ntfsOpenEntry( vd, name );
|
ni = ntfsOpenEntry( vd, name );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that this directory is indeed a directory
|
// Ensure that this directory is indeed a directory
|
||||||
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
if ( !( ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
||||||
|
{
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsCloseEntry( vd, ni );
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
@ -223,7 +231,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( oldName );
|
vd = ntfsGetVolume( oldName );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -232,7 +241,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
|||||||
ntfsLock( vd );
|
ntfsLock( vd );
|
||||||
|
|
||||||
// You cannot rename between devices
|
// You cannot rename between devices
|
||||||
if(vd != ntfsGetVolume(newName)) {
|
if ( vd != ntfsGetVolume( newName ) )
|
||||||
|
{
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
r->_errno = EXDEV;
|
r->_errno = EXDEV;
|
||||||
return -1;
|
return -1;
|
||||||
@ -240,7 +250,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
|||||||
|
|
||||||
// Check that there is no existing entry with the new name
|
// Check that there is no existing entry with the new name
|
||||||
ni = ntfsOpenEntry( vd, newName );
|
ni = ntfsOpenEntry( vd, newName );
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsCloseEntry( vd, ni );
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
@ -248,14 +259,17 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Link the old entry with the new one
|
// Link the old entry with the new one
|
||||||
if (ntfsLink(vd, oldName, newName)) {
|
if ( ntfsLink( vd, oldName, newName ) )
|
||||||
|
{
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlink the old entry
|
// Unlink the old entry
|
||||||
if (ntfsUnlink(vd, oldName)) {
|
if ( ntfsUnlink( vd, oldName ) )
|
||||||
if (ntfsUnlink(vd, newName)) {
|
{
|
||||||
|
if ( ntfsUnlink( vd, newName ) )
|
||||||
|
{
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -278,7 +292,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( path );
|
vd = ntfsGetVolume( path );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -288,7 +303,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
|||||||
|
|
||||||
// Create the directory
|
// Create the directory
|
||||||
ni = ntfsCreate( vd, path, S_IFDIR, NULL );
|
ni = ntfsCreate( vd, path, S_IFDIR, NULL );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock( vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
@ -313,7 +329,8 @@ int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( path );
|
vd = ntfsGetVolume( path );
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -387,21 +404,25 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
|||||||
char *entry_name = NULL;
|
char *entry_name = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!dir || !dir->vd) {
|
if ( !dir || !dir->vd )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore DOS file names
|
// Ignore DOS file names
|
||||||
if (name_type == FILE_NAME_DOS) {
|
if ( name_type == FILE_NAME_DOS )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
|
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
|
||||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles) {
|
if ( MREF( mref ) == FILE_root || MREF( mref ) >= FILE_first_user || dir->vd->showSystemFiles )
|
||||||
|
{
|
||||||
|
|
||||||
// Convert the entry name to our current local
|
// Convert the entry name to our current local
|
||||||
if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0) {
|
if ( ntfsUnicodeToLocal( name, name_len, &entry_name, 0 ) < 0 )
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,7 +433,8 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If this is not the parent or self directory reference
|
// If this is not the parent or self directory reference
|
||||||
if ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0)) {
|
if ( ( strcmp( entry_name, "." ) != 0 ) && ( strcmp( entry_name, ".." ) != 0 ) )
|
||||||
|
{
|
||||||
|
|
||||||
// Open the entry
|
// Open the entry
|
||||||
ntfs_inode *ni = ntfs_pathname_to_inode( dir->vd->vol, dir->ni, entry_name );
|
ntfs_inode *ni = ntfs_pathname_to_inode( dir->vd->vol, dir->ni, entry_name );
|
||||||
@ -421,7 +443,8 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
|||||||
|
|
||||||
// Double check that this entry can be emuerated (as described by the volume descriptor)
|
// Double check that this entry can be emuerated (as described by the volume descriptor)
|
||||||
if ( ( ( ni->flags & FILE_ATTR_HIDDEN ) && !dir->vd->showHiddenFiles ) ||
|
if ( ( ( ni->flags & FILE_ATTR_HIDDEN ) && !dir->vd->showHiddenFiles ) ||
|
||||||
((ni->flags & FILE_ATTR_SYSTEM) && !dir->vd->showSystemFiles)) {
|
( ( ni->flags & FILE_ATTR_SYSTEM ) && !dir->vd->showSystemFiles ) )
|
||||||
|
{
|
||||||
ntfs_inode_close( ni );
|
ntfs_inode_close( ni );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -442,9 +465,12 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
|||||||
entry->mref = MREF( mref );
|
entry->mref = MREF( mref );
|
||||||
|
|
||||||
// Link the entry to the directory
|
// Link the entry to the directory
|
||||||
if (!dir->first) {
|
if ( !dir->first )
|
||||||
|
{
|
||||||
dir->first = entry;
|
dir->first = entry;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_dir_entry *last = dir->first;
|
ntfs_dir_entry *last = dir->first;
|
||||||
while ( last->next ) last = last->next;
|
while ( last->next ) last = last->next;
|
||||||
last->next = entry;
|
last->next = entry;
|
||||||
@ -464,7 +490,8 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
dir->vd = ntfsGetVolume( path );
|
dir->vd = ntfsGetVolume( path );
|
||||||
if (!dir->vd) {
|
if ( !dir->vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -474,14 +501,16 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
|||||||
|
|
||||||
// Find the directory
|
// Find the directory
|
||||||
dir->ni = ntfsOpenEntry( dir->vd, path );
|
dir->ni = ntfsOpenEntry( dir->vd, path );
|
||||||
if (!dir->ni) {
|
if ( !dir->ni )
|
||||||
|
{
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock( dir->vd );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that this directory is indeed a directory
|
// Ensure that this directory is indeed a directory
|
||||||
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
if ( !( dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
||||||
|
{
|
||||||
ntfsCloseEntry( dir->vd, dir->ni );
|
ntfsCloseEntry( dir->vd, dir->ni );
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock( dir->vd );
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
@ -490,7 +519,8 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
|||||||
|
|
||||||
// Read the directory
|
// Read the directory
|
||||||
dir->first = dir->current = NULL;
|
dir->first = dir->current = NULL;
|
||||||
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
|
if ( ntfs_readdir( dir->ni, &position, dirState, ( ntfs_filldir_t )ntfs_readdir_filler ) )
|
||||||
|
{
|
||||||
ntfsCloseDir( dir );
|
ntfsCloseDir( dir );
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock( dir->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
@ -504,10 +534,13 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
|||||||
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
||||||
|
|
||||||
// Insert the directory into the double-linked FILO list of open directories
|
// Insert the directory into the double-linked FILO list of open directories
|
||||||
if (dir->vd->firstOpenDir) {
|
if ( dir->vd->firstOpenDir )
|
||||||
|
{
|
||||||
dir->nextOpenDir = dir->vd->firstOpenDir;
|
dir->nextOpenDir = dir->vd->firstOpenDir;
|
||||||
dir->vd->firstOpenDir->prevOpenDir = dir;
|
dir->vd->firstOpenDir->prevOpenDir = dir;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
dir->nextOpenDir = NULL;
|
dir->nextOpenDir = NULL;
|
||||||
}
|
}
|
||||||
dir->prevOpenDir = NULL;
|
dir->prevOpenDir = NULL;
|
||||||
@ -528,7 +561,8 @@ int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
|||||||
ntfs_dir_state* dir = STATE( dirState );
|
ntfs_dir_state* dir = STATE( dirState );
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!dir || !dir->vd || !dir->ni) {
|
if ( !dir || !dir->vd || !dir->ni )
|
||||||
|
{
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -556,7 +590,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
|||||||
ntfs_inode *ni = NULL;
|
ntfs_inode *ni = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!dir || !dir->vd || !dir->ni) {
|
if ( !dir || !dir->vd || !dir->ni )
|
||||||
|
{
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -565,7 +600,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
|||||||
ntfsLock( dir->vd );
|
ntfsLock( dir->vd );
|
||||||
|
|
||||||
// Check that there is a entry waiting to be fetched
|
// Check that there is a entry waiting to be fetched
|
||||||
if (!dir->current) {
|
if ( !dir->current )
|
||||||
|
{
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock( dir->vd );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -583,7 +619,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ni = ntfsOpenEntry( dir->vd, dir->current->name );
|
ni = ntfsOpenEntry( dir->vd, dir->current->name );
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
ntfsStat( dir->vd, ni, filestat );
|
ntfsStat( dir->vd, ni, filestat );
|
||||||
ntfsCloseEntry( dir->vd, ni );
|
ntfsCloseEntry( dir->vd, ni );
|
||||||
}
|
}
|
||||||
@ -609,7 +646,8 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
|||||||
ntfs_dir_state* dir = STATE( dirState );
|
ntfs_dir_state* dir = STATE( dirState );
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!dir || !dir->vd) {
|
if ( !dir || !dir->vd )
|
||||||
|
{
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@
|
|||||||
/**
|
/**
|
||||||
* ntfs_dir_entry - Directory entry
|
* ntfs_dir_entry - Directory entry
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_dir_entry {
|
typedef struct _ntfs_dir_entry
|
||||||
|
{
|
||||||
char *name;
|
char *name;
|
||||||
u64 mref;
|
u64 mref;
|
||||||
struct _ntfs_dir_entry *next;
|
struct _ntfs_dir_entry *next;
|
||||||
@ -37,7 +38,8 @@ typedef struct _ntfs_dir_entry {
|
|||||||
/**
|
/**
|
||||||
* ntfs_dir_state - Directory state
|
* ntfs_dir_state - Directory state
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_dir_state {
|
typedef struct _ntfs_dir_state
|
||||||
|
{
|
||||||
ntfs_vd *vd; /* Volume this directory belongs to */
|
ntfs_vd *vd; /* Volume this directory belongs to */
|
||||||
ntfs_inode *ni; /* Directory descriptor */
|
ntfs_inode *ni; /* Directory descriptor */
|
||||||
ntfs_dir_entry *first; /* The first entry in the directory */
|
ntfs_dir_entry *first; /* The first entry in the directory */
|
||||||
|
@ -97,7 +97,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
file->vd = ntfsGetVolume( path );
|
file->vd = ntfsGetVolume( path );
|
||||||
if (!file->vd) {
|
if ( !file->vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -107,19 +108,26 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Determine which mode the file is opened for
|
// Determine which mode the file is opened for
|
||||||
file->flags = flags;
|
file->flags = flags;
|
||||||
if ((flags & 0x03) == O_RDONLY) {
|
if ( ( flags & 0x03 ) == O_RDONLY )
|
||||||
|
{
|
||||||
file->read = true;
|
file->read = true;
|
||||||
file->write = false;
|
file->write = false;
|
||||||
file->append = false;
|
file->append = false;
|
||||||
} else if ((flags & 0x03) == O_WRONLY) {
|
}
|
||||||
|
else if ( ( flags & 0x03 ) == O_WRONLY )
|
||||||
|
{
|
||||||
file->read = false;
|
file->read = false;
|
||||||
file->write = true;
|
file->write = true;
|
||||||
file->append = ( flags & O_APPEND );
|
file->append = ( flags & O_APPEND );
|
||||||
} else if ((flags & 0x03) == O_RDWR) {
|
}
|
||||||
|
else if ( ( flags & 0x03 ) == O_RDWR )
|
||||||
|
{
|
||||||
file->read = true;
|
file->read = true;
|
||||||
file->write = true;
|
file->write = true;
|
||||||
file->append = ( flags & O_APPEND );
|
file->append = ( flags & O_APPEND );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
return -1;
|
return -1;
|
||||||
@ -127,7 +135,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Try and find the file and (if found) ensure that it is not a directory
|
// Try and find the file and (if found) ensure that it is not a directory
|
||||||
file->ni = ntfsOpenEntry( file->vd, path );
|
file->ni = ntfsOpenEntry( file->vd, path );
|
||||||
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
if ( file->ni && ( file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||||
|
{
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EISDIR;
|
r->_errno = EISDIR;
|
||||||
@ -135,10 +144,12 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Are we creating this file?
|
// Are we creating this file?
|
||||||
if (flags & O_CREAT) {
|
if ( flags & O_CREAT )
|
||||||
|
{
|
||||||
|
|
||||||
// The file SHOULD NOT already exist
|
// The file SHOULD NOT already exist
|
||||||
if (file->ni) {
|
if ( file->ni )
|
||||||
|
{
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
@ -147,7 +158,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Create the file
|
// Create the file
|
||||||
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
||||||
if (!file->ni) {
|
if ( !file->ni )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -155,7 +167,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check, the file should be open by now
|
// Sanity check, the file should be open by now
|
||||||
if (!file->ni) {
|
if ( !file->ni )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -163,7 +176,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Open the files data attribute
|
// Open the files data attribute
|
||||||
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
||||||
if(!file->data_na) {
|
if ( !file->data_na )
|
||||||
|
{
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
return -1;
|
return -1;
|
||||||
@ -174,7 +188,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
file->encrypted = NAttrEncrypted( file->data_na ) || ( file->ni->flags & FILE_ATTR_ENCRYPTED );
|
file->encrypted = NAttrEncrypted( file->data_na ) || ( file->ni->flags & FILE_ATTR_ENCRYPTED );
|
||||||
|
|
||||||
// We cannot read/write encrypted files
|
// We cannot read/write encrypted files
|
||||||
if (file->encrypted) {
|
if ( file->encrypted )
|
||||||
|
{
|
||||||
ntfs_attr_close( file->data_na );
|
ntfs_attr_close( file->data_na );
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
@ -183,7 +198,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we aren't trying to write to a read-only file
|
// Make sure we aren't trying to write to a read-only file
|
||||||
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
|
if ( ( file->ni->flags & FILE_ATTR_READONLY ) && file->write )
|
||||||
|
{
|
||||||
ntfs_attr_close( file->data_na );
|
ntfs_attr_close( file->data_na );
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
@ -192,8 +208,10 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Truncate the file if requested
|
// Truncate the file if requested
|
||||||
if ((flags & O_TRUNC) && file->write) {
|
if ( ( flags & O_TRUNC ) && file->write )
|
||||||
if (ntfs_attr_truncate(file->data_na, 0)) {
|
{
|
||||||
|
if ( ntfs_attr_truncate( file->data_na, 0 ) )
|
||||||
|
{
|
||||||
ntfs_attr_close( file->data_na );
|
ntfs_attr_close( file->data_na );
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
@ -212,10 +230,13 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
|
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
|
||||||
|
|
||||||
// Insert the file into the double-linked FILO list of open files
|
// Insert the file into the double-linked FILO list of open files
|
||||||
if (file->vd->firstOpenFile) {
|
if ( file->vd->firstOpenFile )
|
||||||
|
{
|
||||||
file->nextOpenFile = file->vd->firstOpenFile;
|
file->nextOpenFile = file->vd->firstOpenFile;
|
||||||
file->vd->firstOpenFile->prevOpenFile = file;
|
file->vd->firstOpenFile->prevOpenFile = file;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
file->nextOpenFile = NULL;
|
file->nextOpenFile = NULL;
|
||||||
}
|
}
|
||||||
file->prevOpenFile = NULL;
|
file->prevOpenFile = NULL;
|
||||||
@ -235,7 +256,8 @@ int ntfs_close_r (struct _reent *r, int fd)
|
|||||||
ntfs_file_state* file = STATE( fd );
|
ntfs_file_state* file = STATE( fd );
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd) {
|
if ( !file || !file->vd )
|
||||||
|
{
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -270,13 +292,15 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
|||||||
off_t old_pos = 0;
|
off_t old_pos = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases where we don't actually have to do anything
|
// Short circuit cases where we don't actually have to do anything
|
||||||
if (!ptr || len <= 0) {
|
if ( !ptr || len <= 0 )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,22 +308,26 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
|||||||
ntfsLock( file->vd );
|
ntfsLock( file->vd );
|
||||||
|
|
||||||
// Check that we are allowed to write to this file
|
// Check that we are allowed to write to this file
|
||||||
if (!file->write) {
|
if ( !file->write )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are in append mode, backup the current position and move to the end of the file
|
// If we are in append mode, backup the current position and move to the end of the file
|
||||||
if (file->append) {
|
if ( file->append )
|
||||||
|
{
|
||||||
old_pos = file->pos;
|
old_pos = file->pos;
|
||||||
file->pos = file->len;
|
file->pos = file->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to the files data atrribute
|
// Write to the files data atrribute
|
||||||
while (len) {
|
while ( len )
|
||||||
|
{
|
||||||
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
||||||
if (ret <= 0) {
|
if ( ret <= 0 )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
@ -310,7 +338,8 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we are in append mode, restore the current position to were it was prior to this write
|
// If we are in append mode, restore the current position to were it was prior to this write
|
||||||
if (file->append) {
|
if ( file->append )
|
||||||
|
{
|
||||||
file->pos = old_pos;
|
file->pos = old_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,13 +364,15 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
|||||||
ssize_t read = 0;
|
ssize_t read = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases where we don't actually have to do anything
|
// Short circuit cases where we don't actually have to do anything
|
||||||
if (!ptr || len <= 0) {
|
if ( !ptr || len <= 0 )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,14 +380,16 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
|||||||
ntfsLock( file->vd );
|
ntfsLock( file->vd );
|
||||||
|
|
||||||
// Check that we are allowed to read from this file
|
// Check that we are allowed to read from this file
|
||||||
if (!file->read) {
|
if ( !file->read )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't read past the end of file
|
// Don't read past the end of file
|
||||||
if (file->pos + len > file->len) {
|
if ( file->pos + len > file->len )
|
||||||
|
{
|
||||||
r->_errno = EOVERFLOW;
|
r->_errno = EOVERFLOW;
|
||||||
len = file->len - file->pos;
|
len = file->len - file->pos;
|
||||||
ntfs_log_trace( "EOVERFLOW" );
|
ntfs_log_trace( "EOVERFLOW" );
|
||||||
@ -365,9 +398,11 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
|||||||
ntfs_log_trace( "file->pos:%d, len:%d, file->len:%d \n", ( u32 )file->pos, ( u32 )len, ( u32 )file->len );
|
ntfs_log_trace( "file->pos:%d, len:%d, file->len:%d \n", ( u32 )file->pos, ( u32 )len, ( u32 )file->len );
|
||||||
|
|
||||||
// Read from the files data attribute
|
// Read from the files data attribute
|
||||||
while (len) {
|
while ( len )
|
||||||
|
{
|
||||||
ssize_t ret = ntfs_attr_pread( file->data_na, file->pos, len, ptr );
|
ssize_t ret = ntfs_attr_pread( file->data_na, file->pos, len, ptr );
|
||||||
if (ret <= 0 || ret > len) {
|
if ( ret <= 0 || ret > len )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
@ -394,7 +429,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
|||||||
off_t position = 0;
|
off_t position = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -403,7 +439,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
|||||||
ntfsLock( file->vd );
|
ntfsLock( file->vd );
|
||||||
|
|
||||||
// Set the files current position
|
// Set the files current position
|
||||||
switch(dir) {
|
switch ( dir )
|
||||||
|
{
|
||||||
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break;
|
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break;
|
||||||
case SEEK_CUR: position = file->pos = MIN( MAX( file->pos + pos, 0 ), file->len ); break;
|
case SEEK_CUR: position = file->pos = MIN( MAX( file->pos + pos, 0 ), file->len ); break;
|
||||||
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
||||||
@ -422,7 +459,8 @@ int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -446,7 +484,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
|||||||
ntfs_file_state* file = STATE( fd );
|
ntfs_file_state* file = STATE( fd );
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -455,7 +494,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
|||||||
ntfsLock( file->vd );
|
ntfsLock( file->vd );
|
||||||
|
|
||||||
// Check that we are allowed to write to this file
|
// Check that we are allowed to write to this file
|
||||||
if (!file->write) {
|
if ( !file->write )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
@ -464,22 +504,28 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
|||||||
// For compressed files, only deleting and expanding contents are implemented
|
// For compressed files, only deleting and expanding contents are implemented
|
||||||
if ( file->compressed &&
|
if ( file->compressed &&
|
||||||
len > 0 &&
|
len > 0 &&
|
||||||
len < file->data_na->initialized_size) {
|
len < file->data_na->initialized_size )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EOPNOTSUPP;
|
r->_errno = EOPNOTSUPP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize the files data attribute, either by expanding or truncating
|
// Resize the files data attribute, either by expanding or truncating
|
||||||
if (file->compressed && len > file->data_na->initialized_size) {
|
if ( file->compressed && len > file->data_na->initialized_size )
|
||||||
|
{
|
||||||
char zero = 0;
|
char zero = 0;
|
||||||
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
|
if ( ntfs_attr_pwrite( file->data_na, len - 1, 1, &zero ) <= 0 )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (ntfs_attr_truncate(file->data_na, len)) {
|
else
|
||||||
|
{
|
||||||
|
if ( ntfs_attr_truncate( file->data_na, len ) )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
@ -514,7 +560,8 @@ int ntfs_fsync_r (struct _reent *r, int fd)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
/**
|
/**
|
||||||
* ntfs_file_state - File state
|
* ntfs_file_state - File state
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_file_state {
|
typedef struct _ntfs_file_state
|
||||||
|
{
|
||||||
ntfs_vd *vd; /* Volume this file belongs to */
|
ntfs_vd *vd; /* Volume this file belongs to */
|
||||||
ntfs_inode *ni; /* File descriptor */
|
ntfs_inode *ni; /* File descriptor */
|
||||||
ntfs_attr *data_na; /* File data descriptor */
|
ntfs_attr *data_na; /* File data descriptor */
|
||||||
|
@ -102,7 +102,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
file->vd = ntfsGetVolume( path );
|
file->vd = ntfsGetVolume( path );
|
||||||
if (!file->vd) {
|
if ( !file->vd )
|
||||||
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -112,19 +113,26 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Determine which mode the file is opened for
|
// Determine which mode the file is opened for
|
||||||
file->flags = flags;
|
file->flags = flags;
|
||||||
if ((flags & 0x03) == O_RDONLY) {
|
if ( ( flags & 0x03 ) == O_RDONLY )
|
||||||
|
{
|
||||||
file->read = true;
|
file->read = true;
|
||||||
file->write = false;
|
file->write = false;
|
||||||
file->append = false;
|
file->append = false;
|
||||||
} else if ((flags & 0x03) == O_WRONLY) {
|
}
|
||||||
|
else if ( ( flags & 0x03 ) == O_WRONLY )
|
||||||
|
{
|
||||||
file->read = false;
|
file->read = false;
|
||||||
file->write = true;
|
file->write = true;
|
||||||
file->append = ( flags & O_APPEND );
|
file->append = ( flags & O_APPEND );
|
||||||
} else if ((flags & 0x03) == O_RDWR) {
|
}
|
||||||
|
else if ( ( flags & 0x03 ) == O_RDWR )
|
||||||
|
{
|
||||||
file->read = true;
|
file->read = true;
|
||||||
file->write = true;
|
file->write = true;
|
||||||
file->append = ( flags & O_APPEND );
|
file->append = ( flags & O_APPEND );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
return -1;
|
return -1;
|
||||||
@ -132,7 +140,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Try and find the file and (if found) ensure that it is not a directory
|
// Try and find the file and (if found) ensure that it is not a directory
|
||||||
file->ni = ntfsOpenEntry( file->vd, path );
|
file->ni = ntfsOpenEntry( file->vd, path );
|
||||||
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
if ( file->ni && ( file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||||
|
{
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EISDIR;
|
r->_errno = EISDIR;
|
||||||
@ -140,10 +149,12 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Are we creating this file?
|
// Are we creating this file?
|
||||||
if (flags & O_CREAT) {
|
if ( flags & O_CREAT )
|
||||||
|
{
|
||||||
|
|
||||||
// The file SHOULD NOT already exist
|
// The file SHOULD NOT already exist
|
||||||
if (file->ni) {
|
if ( file->ni )
|
||||||
|
{
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
@ -152,7 +163,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Create the file
|
// Create the file
|
||||||
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
||||||
if (!file->ni) {
|
if ( !file->ni )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -160,7 +172,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check, the file should be open by now
|
// Sanity check, the file should be open by now
|
||||||
if (!file->ni) {
|
if ( !file->ni )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -168,7 +181,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
// Open the files data attribute
|
// Open the files data attribute
|
||||||
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
||||||
if(!file->data_na) {
|
if ( !file->data_na )
|
||||||
|
{
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
return -1;
|
return -1;
|
||||||
@ -179,7 +193,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
file->encrypted = NAttrEncrypted( file->data_na ) || ( file->ni->flags & FILE_ATTR_ENCRYPTED );
|
file->encrypted = NAttrEncrypted( file->data_na ) || ( file->ni->flags & FILE_ATTR_ENCRYPTED );
|
||||||
|
|
||||||
// We cannot read/write encrypted files
|
// We cannot read/write encrypted files
|
||||||
if (file->encrypted) {
|
if ( file->encrypted )
|
||||||
|
{
|
||||||
ntfs_attr_close( file->data_na );
|
ntfs_attr_close( file->data_na );
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
@ -188,7 +203,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we aren't trying to write to a read-only file
|
// Make sure we aren't trying to write to a read-only file
|
||||||
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
|
if ( ( file->ni->flags & FILE_ATTR_READONLY ) && file->write )
|
||||||
|
{
|
||||||
ntfs_attr_close( file->data_na );
|
ntfs_attr_close( file->data_na );
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
@ -197,8 +213,10 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Truncate the file if requested
|
// Truncate the file if requested
|
||||||
if ((flags & O_TRUNC) && file->write) {
|
if ( ( flags & O_TRUNC ) && file->write )
|
||||||
if (ntfs_attr_truncate(file->data_na, 0)) {
|
{
|
||||||
|
if ( ntfs_attr_truncate( file->data_na, 0 ) )
|
||||||
|
{
|
||||||
ntfs_attr_close( file->data_na );
|
ntfs_attr_close( file->data_na );
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry( file->vd, file->ni );
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
@ -217,10 +235,13 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
|
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
|
||||||
|
|
||||||
// Insert the file into the double-linked FILO list of open files
|
// Insert the file into the double-linked FILO list of open files
|
||||||
if (file->vd->firstOpenFile) {
|
if ( file->vd->firstOpenFile )
|
||||||
|
{
|
||||||
file->nextOpenFile = file->vd->firstOpenFile;
|
file->nextOpenFile = file->vd->firstOpenFile;
|
||||||
file->vd->firstOpenFile->prevOpenFile = file;
|
file->vd->firstOpenFile->prevOpenFile = file;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
file->nextOpenFile = NULL;
|
file->nextOpenFile = NULL;
|
||||||
}
|
}
|
||||||
file->prevOpenFile = NULL;
|
file->prevOpenFile = NULL;
|
||||||
@ -240,7 +261,8 @@ int ntfs_close_r (struct _reent *r, int fd)
|
|||||||
ntfs_file_state* file = STATE( fd );
|
ntfs_file_state* file = STATE( fd );
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd) {
|
if ( !file || !file->vd )
|
||||||
|
{
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -275,13 +297,15 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
|||||||
off_t old_pos = 0;
|
off_t old_pos = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases where we don't actually have to do anything
|
// Short circuit cases where we don't actually have to do anything
|
||||||
if (!ptr || len <= 0) {
|
if ( !ptr || len <= 0 )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,22 +313,26 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
|||||||
ntfsLock( file->vd );
|
ntfsLock( file->vd );
|
||||||
|
|
||||||
// Check that we are allowed to write to this file
|
// Check that we are allowed to write to this file
|
||||||
if (!file->write) {
|
if ( !file->write )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are in append mode, backup the current position and move to the end of the file
|
// If we are in append mode, backup the current position and move to the end of the file
|
||||||
if (file->append) {
|
if ( file->append )
|
||||||
|
{
|
||||||
old_pos = file->pos;
|
old_pos = file->pos;
|
||||||
file->pos = file->len;
|
file->pos = file->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to the files data atrribute
|
// Write to the files data atrribute
|
||||||
while (len) {
|
while ( len )
|
||||||
|
{
|
||||||
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
||||||
if (ret <= 0) {
|
if ( ret <= 0 )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
@ -315,7 +343,8 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we are in append mode, restore the current position to were it was prior to this write
|
// If we are in append mode, restore the current position to were it was prior to this write
|
||||||
if (file->append) {
|
if ( file->append )
|
||||||
|
{
|
||||||
file->pos = old_pos;
|
file->pos = old_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,7 +384,8 @@ int _NTFS_get_fragments (const char *path,
|
|||||||
|
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
//r->_errno = EINVAL;
|
//r->_errno = EINVAL;
|
||||||
return -13;
|
return -13;
|
||||||
}
|
}
|
||||||
@ -389,10 +419,12 @@ int _NTFS_get_fragments (const char *path,
|
|||||||
u64 len = file->len;
|
u64 len = file->len;
|
||||||
|
|
||||||
// Read from the files data attribute
|
// Read from the files data attribute
|
||||||
while (len) {
|
while ( len )
|
||||||
|
{
|
||||||
s64 ret = ntfs_attr_getfragments( file->data_na, file->pos,
|
s64 ret = ntfs_attr_getfragments( file->data_na, file->pos,
|
||||||
len, offset, append_fragment, callback_data );
|
len, offset, append_fragment, callback_data );
|
||||||
if (ret <= 0 || ret > len) {
|
if ( ret <= 0 || ret > len )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
//r->_errno = errno;
|
//r->_errno = errno;
|
||||||
ret_val = -14;
|
ret_val = -14;
|
||||||
@ -436,7 +468,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
|||||||
off_t position = 0;
|
off_t position = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -445,7 +478,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
|||||||
ntfsLock( file->vd );
|
ntfsLock( file->vd );
|
||||||
|
|
||||||
// Set the files current position
|
// Set the files current position
|
||||||
switch(dir) {
|
switch ( dir )
|
||||||
|
{
|
||||||
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break;
|
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break;
|
||||||
case SEEK_CUR: position = file->pos = MIN( MAX( file->pos + pos, 0 ), file->len ); break;
|
case SEEK_CUR: position = file->pos = MIN( MAX( file->pos + pos, 0 ), file->len ); break;
|
||||||
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
||||||
@ -464,7 +498,8 @@ int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -488,7 +523,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
|||||||
ntfs_file_state* file = STATE( fd );
|
ntfs_file_state* file = STATE( fd );
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -497,7 +533,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
|||||||
ntfsLock( file->vd );
|
ntfsLock( file->vd );
|
||||||
|
|
||||||
// Check that we are allowed to write to this file
|
// Check that we are allowed to write to this file
|
||||||
if (!file->write) {
|
if ( !file->write )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
@ -506,22 +543,28 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
|||||||
// For compressed files, only deleting and expanding contents are implemented
|
// For compressed files, only deleting and expanding contents are implemented
|
||||||
if ( file->compressed &&
|
if ( file->compressed &&
|
||||||
len > 0 &&
|
len > 0 &&
|
||||||
len < file->data_na->initialized_size) {
|
len < file->data_na->initialized_size )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = EOPNOTSUPP;
|
r->_errno = EOPNOTSUPP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize the files data attribute, either by expanding or truncating
|
// Resize the files data attribute, either by expanding or truncating
|
||||||
if (file->compressed && len > file->data_na->initialized_size) {
|
if ( file->compressed && len > file->data_na->initialized_size )
|
||||||
|
{
|
||||||
char zero = 0;
|
char zero = 0;
|
||||||
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
|
if ( ntfs_attr_pwrite( file->data_na, len - 1, 1, &zero ) <= 0 )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (ntfs_attr_truncate(file->data_na, len)) {
|
else
|
||||||
|
{
|
||||||
|
if ( ntfs_attr_truncate( file->data_na, len ) )
|
||||||
|
{
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock( file->vd );
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
@ -556,7 +599,8 @@ int ntfs_fsync_r (struct _reent *r, int fd)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||||
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@
|
|||||||
#include <sdcard/gcsd.h>
|
#include <sdcard/gcsd.h>
|
||||||
#include <ogc/usbstorage.h>
|
#include <ogc/usbstorage.h>
|
||||||
|
|
||||||
const INTERFACE_ID ntfs_disc_interfaces[] = {
|
const INTERFACE_ID ntfs_disc_interfaces[] =
|
||||||
|
{
|
||||||
{ "sd", &__io_wiisd },
|
{ "sd", &__io_wiisd },
|
||||||
{ "usb", &__io_usbstorage },
|
{ "usb", &__io_usbstorage },
|
||||||
{ "carda", &__io_gcsda },
|
{ "carda", &__io_gcsda },
|
||||||
@ -54,7 +55,8 @@ const INTERFACE_ID ntfs_disc_interfaces[] = {
|
|||||||
#elif defined(__gamecube__)
|
#elif defined(__gamecube__)
|
||||||
#include <sdcard/gcsd.h>
|
#include <sdcard/gcsd.h>
|
||||||
|
|
||||||
const INTERFACE_ID ntfs_disc_interfaces[] = {
|
const INTERFACE_ID ntfs_disc_interfaces[] =
|
||||||
|
{
|
||||||
{ "carda", &__io_gcsda },
|
{ "carda", &__io_gcsda },
|
||||||
{ "cardb", &__io_gcsdb },
|
{ "cardb", &__io_gcsdb },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
@ -70,14 +72,16 @@ int ntfsAddDevice (const char *name, void *deviceData)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!name || !deviceData || !devoptab_ntfs) {
|
if ( !name || !deviceData || !devoptab_ntfs )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a devoptab for this device
|
// Allocate a devoptab for this device
|
||||||
dev = ( devoptab_t * ) ntfs_alloc( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
dev = ( devoptab_t * ) ntfs_alloc( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
||||||
if (!dev) {
|
if ( !dev )
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -92,8 +96,10 @@ int ntfsAddDevice (const char *name, void *deviceData)
|
|||||||
dev->deviceData = deviceData;
|
dev->deviceData = deviceData;
|
||||||
|
|
||||||
// Add the device to the devoptab table (if there is a free slot)
|
// Add the device to the devoptab table (if there is a free slot)
|
||||||
for (i = 0; i < STD_MAX; i++) {
|
for ( i = 0; i < STD_MAX; i++ )
|
||||||
if (devoptab_list[i] == devoptab_list[0] && i != 0) {
|
{
|
||||||
|
if ( devoptab_list[i] == devoptab_list[0] && i != 0 )
|
||||||
|
{
|
||||||
devoptab_list[i] = dev;
|
devoptab_list[i] = dev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -118,10 +124,13 @@ void ntfsRemoveDevice (const char *path)
|
|||||||
// NOTE: We do this manually due to a 'bug' in RemoveDevice
|
// NOTE: We do this manually due to a 'bug' in RemoveDevice
|
||||||
// which ignores names with suffixes and causes names
|
// which ignores names with suffixes and causes names
|
||||||
// like "ntfs" and "ntfs1" to be seen as equals
|
// like "ntfs" and "ntfs1" to be seen as equals
|
||||||
for (i = 0; i < STD_MAX; i++) {
|
for ( i = 0; i < STD_MAX; i++ )
|
||||||
|
{
|
||||||
devoptab = devoptab_list[i];
|
devoptab = devoptab_list[i];
|
||||||
if (devoptab && devoptab->name) {
|
if ( devoptab && devoptab->name )
|
||||||
if (strcmp(name, devoptab->name) == 0) {
|
{
|
||||||
|
if ( strcmp( name, devoptab->name ) == 0 )
|
||||||
|
{
|
||||||
devoptab_list[i] = devoptab_list[0];
|
devoptab_list[i] = devoptab_list[0];
|
||||||
ntfs_free( ( devoptab_t* )devoptab );
|
ntfs_free( ( devoptab_t* )devoptab );
|
||||||
break;
|
break;
|
||||||
@ -146,10 +155,13 @@ const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice)
|
|||||||
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
|
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
|
||||||
// which ignores names with suffixes and causes names
|
// which ignores names with suffixes and causes names
|
||||||
// like "ntfs" and "ntfs1" to be seen as equals
|
// like "ntfs" and "ntfs1" to be seen as equals
|
||||||
for (i = 0; i < STD_MAX; i++) {
|
for ( i = 0; i < STD_MAX; i++ )
|
||||||
|
{
|
||||||
devoptab = devoptab_list[i];
|
devoptab = devoptab_list[i];
|
||||||
if (devoptab && devoptab->name) {
|
if ( devoptab && devoptab->name )
|
||||||
if (strcmp(name, devoptab->name) == 0) {
|
{
|
||||||
|
if ( strcmp( name, devoptab->name ) == 0 )
|
||||||
|
{
|
||||||
return devoptab;
|
return devoptab;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,7 +196,8 @@ ntfs_vd *ntfsGetVolume (const char *path)
|
|||||||
int ntfsInitVolume ( ntfs_vd *vd )
|
int ntfsInitVolume ( ntfs_vd *vd )
|
||||||
{
|
{
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -210,7 +223,8 @@ int ntfsInitVolume (ntfs_vd *vd)
|
|||||||
void ntfsDeinitVolume ( ntfs_vd *vd )
|
void ntfsDeinitVolume ( ntfs_vd *vd )
|
||||||
{
|
{
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -220,7 +234,8 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
|||||||
|
|
||||||
// Close any directories which are still open (lazy programmers!)
|
// Close any directories which are still open (lazy programmers!)
|
||||||
ntfs_dir_state *nextDir = vd->firstOpenDir;
|
ntfs_dir_state *nextDir = vd->firstOpenDir;
|
||||||
while (nextDir) {
|
while ( nextDir )
|
||||||
|
{
|
||||||
ntfs_log_warning( "Cleaning up orphaned directory @ %p\n", nextDir );
|
ntfs_log_warning( "Cleaning up orphaned directory @ %p\n", nextDir );
|
||||||
ntfsCloseDir( nextDir );
|
ntfsCloseDir( nextDir );
|
||||||
nextDir = nextDir->nextOpenDir;
|
nextDir = nextDir->nextOpenDir;
|
||||||
@ -228,7 +243,8 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
|||||||
|
|
||||||
// Close any files which are still open (lazy programmers!)
|
// Close any files which are still open (lazy programmers!)
|
||||||
ntfs_file_state *nextFile = vd->firstOpenFile;
|
ntfs_file_state *nextFile = vd->firstOpenFile;
|
||||||
while (nextFile) {
|
while ( nextFile )
|
||||||
|
{
|
||||||
ntfs_log_warning( "Cleaning up orphaned file @ %p\n", nextFile );
|
ntfs_log_warning( "Cleaning up orphaned file @ %p\n", nextFile );
|
||||||
ntfsCloseFile( nextFile );
|
ntfsCloseFile( nextFile );
|
||||||
nextFile = nextFile->nextOpenFile;
|
nextFile = nextFile->nextOpenFile;
|
||||||
@ -270,17 +286,21 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
|||||||
int attr_size;
|
int attr_size;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the actual path of the entry
|
// Get the actual path of the entry
|
||||||
path = ntfsRealPath( path );
|
path = ntfsRealPath( path );
|
||||||
if (!path) {
|
if ( !path )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (path[0] == '\0') {
|
}
|
||||||
|
else if ( path[0] == '\0' )
|
||||||
|
{
|
||||||
path = ".";
|
path = ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,11 +312,14 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
|||||||
|
|
||||||
// If the entry was found and it has reparse data then parse its true path;
|
// If the entry was found and it has reparse data then parse its true path;
|
||||||
// this resolves the true location of symbolic links and directory junctions
|
// this resolves the true location of symbolic links and directory junctions
|
||||||
if (ni && (ni->flags & FILE_ATTR_REPARSE_POINT)) {
|
if ( ni && ( ni->flags & FILE_ATTR_REPARSE_POINT ) )
|
||||||
if (ntfs_possible_symlink(ni)) {
|
{
|
||||||
|
if ( ntfs_possible_symlink( ni ) )
|
||||||
|
{
|
||||||
|
|
||||||
// Sanity check, give up if we are parsing to deep
|
// Sanity check, give up if we are parsing to deep
|
||||||
if (reparseLevel > NTFS_MAX_SYMLINK_DEPTH) {
|
if ( reparseLevel > NTFS_MAX_SYMLINK_DEPTH )
|
||||||
|
{
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsCloseEntry( vd, ni );
|
||||||
errno = ELOOP;
|
errno = ELOOP;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -304,7 +327,8 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
|||||||
|
|
||||||
// Get the target path of this entry
|
// Get the target path of this entry
|
||||||
target = ntfs_make_symlink( ni, path, &attr_size );
|
target = ntfs_make_symlink( ni, path, &attr_size );
|
||||||
if (!target) {
|
if ( !target )
|
||||||
|
{
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsCloseEntry( vd, ni );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -327,7 +351,8 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
|||||||
void ntfsCloseEntry ( ntfs_vd *vd, ntfs_inode *ni )
|
void ntfsCloseEntry ( ntfs_vd *vd, ntfs_inode *ni )
|
||||||
{
|
{
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -358,14 +383,17 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
|||||||
int uname_len, utarget_len;
|
int uname_len, utarget_len;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// You cannot link between devices
|
// You cannot link between devices
|
||||||
if(target) {
|
if ( target )
|
||||||
if(vd != ntfsGetVolume(target)) {
|
{
|
||||||
|
if ( vd != ntfsGetVolume( target ) )
|
||||||
|
{
|
||||||
errno = EXDEV;
|
errno = EXDEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -374,7 +402,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
|||||||
// Get the actual paths of the entry
|
// Get the actual paths of the entry
|
||||||
path = ntfsRealPath( path );
|
path = ntfsRealPath( path );
|
||||||
target = ntfsRealPath( target );
|
target = ntfsRealPath( target );
|
||||||
if (!path) {
|
if ( !path )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -385,7 +414,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
|||||||
// Get the unicode name for the entry and find its parent directory
|
// Get the unicode name for the entry and find its parent directory
|
||||||
// TODO: This looks horrible, clean it up
|
// TODO: This looks horrible, clean it up
|
||||||
dir = strdup( path );
|
dir = strdup( path );
|
||||||
if (!dir) {
|
if ( !dir )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -395,7 +425,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
|||||||
else
|
else
|
||||||
name = dir;
|
name = dir;
|
||||||
uname_len = ntfsLocalToUnicode( name, &uname );
|
uname_len = ntfsLocalToUnicode( name, &uname );
|
||||||
if (uname_len < 0) {
|
if ( uname_len < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -408,21 +439,25 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
|||||||
|
|
||||||
// Open the entries parent directory
|
// Open the entries parent directory
|
||||||
dir_ni = ntfsOpenEntry( vd, dir );
|
dir_ni = ntfsOpenEntry( vd, dir );
|
||||||
if (!dir_ni) {
|
if ( !dir_ni )
|
||||||
|
{
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the entry
|
// Create the entry
|
||||||
switch (type) {
|
switch ( type )
|
||||||
|
{
|
||||||
|
|
||||||
// Symbolic link
|
// Symbolic link
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
if (!target) {
|
if ( !target )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
utarget_len = ntfsLocalToUnicode( target, &utarget );
|
utarget_len = ntfsLocalToUnicode( target, &utarget );
|
||||||
if (utarget_len < 0) {
|
if ( utarget_len < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -438,7 +473,8 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the entry was created
|
// If the entry was created
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
|
|
||||||
// Mark the entry for archiving
|
// Mark the entry for archiving
|
||||||
ni->flags |= FILE_ATTR_ARCHIVE;
|
ni->flags |= FILE_ATTR_ARCHIVE;
|
||||||
@ -484,13 +520,15 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// You cannot link between devices
|
// You cannot link between devices
|
||||||
if(vd != ntfsGetVolume(new_path)) {
|
if ( vd != ntfsGetVolume( new_path ) )
|
||||||
|
{
|
||||||
errno = EXDEV;
|
errno = EXDEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -498,7 +536,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
|||||||
// Get the actual paths of the entry
|
// Get the actual paths of the entry
|
||||||
old_path = ntfsRealPath( old_path );
|
old_path = ntfsRealPath( old_path );
|
||||||
new_path = ntfsRealPath( new_path );
|
new_path = ntfsRealPath( new_path );
|
||||||
if (!old_path || !new_path) {
|
if ( !old_path || !new_path )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -509,7 +548,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
|||||||
// Get the unicode name for the entry and find its parent directory
|
// Get the unicode name for the entry and find its parent directory
|
||||||
// TODO: This looks horrible, clean it up
|
// TODO: This looks horrible, clean it up
|
||||||
dir = strdup( new_path );
|
dir = strdup( new_path );
|
||||||
if (!dir) {
|
if ( !dir )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -519,7 +559,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
|||||||
else
|
else
|
||||||
name = dir;
|
name = dir;
|
||||||
uname_len = ntfsLocalToUnicode( name, &uname );
|
uname_len = ntfsLocalToUnicode( name, &uname );
|
||||||
if (uname_len < 0) {
|
if ( uname_len < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -527,7 +568,8 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
|||||||
|
|
||||||
// Find the entry
|
// Find the entry
|
||||||
ni = ntfsOpenEntry( vd, old_path );
|
ni = ntfsOpenEntry( vd, old_path );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
res = -1;
|
res = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -535,14 +577,16 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
|||||||
|
|
||||||
// Open the entries new parent directory
|
// Open the entries new parent directory
|
||||||
dir_ni = ntfsOpenEntry( vd, dir );
|
dir_ni = ntfsOpenEntry( vd, dir );
|
||||||
if (!dir_ni) {
|
if ( !dir_ni )
|
||||||
|
{
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
res = -1;
|
res = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link the entry to its new parent
|
// Link the entry to its new parent
|
||||||
if (ntfs_link(ni, dir_ni, uname, uname_len)) {
|
if ( ntfs_link( ni, dir_ni, uname, uname_len ) )
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -583,14 +627,16 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the actual path of the entry
|
// Get the actual path of the entry
|
||||||
path = ntfsRealPath( path );
|
path = ntfsRealPath( path );
|
||||||
if (!path) {
|
if ( !path )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -601,7 +647,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
|||||||
// Get the unicode name for the entry and find its parent directory
|
// Get the unicode name for the entry and find its parent directory
|
||||||
// TODO: This looks horrible
|
// TODO: This looks horrible
|
||||||
dir = strdup( path );
|
dir = strdup( path );
|
||||||
if (!dir) {
|
if ( !dir )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -611,7 +658,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
|||||||
else
|
else
|
||||||
name = dir;
|
name = dir;
|
||||||
uname_len = ntfsLocalToUnicode( name, &uname );
|
uname_len = ntfsLocalToUnicode( name, &uname );
|
||||||
if (uname_len < 0) {
|
if ( uname_len < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -624,7 +672,8 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
|||||||
|
|
||||||
// Find the entry
|
// Find the entry
|
||||||
ni = ntfsOpenEntry( vd, path );
|
ni = ntfsOpenEntry( vd, path );
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
res = -1;
|
res = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -632,14 +681,16 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
|||||||
|
|
||||||
// Open the entries parent directory
|
// Open the entries parent directory
|
||||||
dir_ni = ntfsOpenEntry( vd, dir );
|
dir_ni = ntfsOpenEntry( vd, dir );
|
||||||
if (!dir_ni) {
|
if ( !dir_ni )
|
||||||
|
{
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
res = -1;
|
res = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlink the entry from its parent
|
// Unlink the entry from its parent
|
||||||
if (ntfs_delete(vd->vol, path, ni, dir_ni, uname, uname_len)) {
|
if ( ntfs_delete( vd->vol, path, ni, dir_ni, uname, uname_len ) )
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,13 +725,15 @@ int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -707,13 +760,15 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!vd) {
|
if ( !vd )
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!ni) {
|
if ( !ni )
|
||||||
|
{
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -729,20 +784,24 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
|||||||
memset( st, 0, sizeof( struct stat ) );
|
memset( st, 0, sizeof( struct stat ) );
|
||||||
|
|
||||||
// Is this entry a directory
|
// Is this entry a directory
|
||||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
if ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
|
||||||
|
{
|
||||||
st->st_mode = S_IFDIR | ( 0777 & ~vd->dmask );
|
st->st_mode = S_IFDIR | ( 0777 & ~vd->dmask );
|
||||||
st->st_nlink = 1;
|
st->st_nlink = 1;
|
||||||
|
|
||||||
// Open the directories index allocation table attribute
|
// Open the directories index allocation table attribute
|
||||||
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4 );
|
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
st->st_size = na->data_size;
|
st->st_size = na->data_size;
|
||||||
st->st_blocks = na->allocated_size >> 9;
|
st->st_blocks = na->allocated_size >> 9;
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else it must be a file
|
// Else it must be a file
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
st->st_mode = S_IFREG | ( 0777 & ~vd->fmask );
|
st->st_mode = S_IFREG | ( 0777 & ~vd->fmask );
|
||||||
st->st_size = ni->data_size;
|
st->st_size = ni->data_size;
|
||||||
st->st_blocks = ( ni->allocated_size + 511 ) >> 9;
|
st->st_blocks = ( ni->allocated_size + 511 ) >> 9;
|
||||||
@ -787,10 +846,12 @@ const char *ntfsRealPath (const char *path)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if (strchr(path, ':') != NULL) {
|
if ( strchr( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
path = strchr( path, ':' ) + 1;
|
path = strchr( path, ':' ) + 1;
|
||||||
}
|
}
|
||||||
if (strchr(path, ':') != NULL) {
|
if ( strchr( path, ':' ) != NULL )
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,19 +869,24 @@ int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int
|
|||||||
|
|
||||||
// Convert the unicode string to our current local
|
// Convert the unicode string to our current local
|
||||||
len = ntfs_ucstombs( ins, ins_len, outs, outs_len );
|
len = ntfs_ucstombs( ins, ins_len, outs, outs_len );
|
||||||
if (len == -1 && errno == EILSEQ) {
|
if ( len == -1 && errno == EILSEQ )
|
||||||
|
{
|
||||||
|
|
||||||
// The string could not be converted to the current local,
|
// The string could not be converted to the current local,
|
||||||
// do it manually by replacing non-ASCII characters with underscores
|
// do it manually by replacing non-ASCII characters with underscores
|
||||||
if (!*outs || outs_len >= ins_len) {
|
if ( !*outs || outs_len >= ins_len )
|
||||||
if (!*outs) {
|
{
|
||||||
|
if ( !*outs )
|
||||||
|
{
|
||||||
*outs = ( char * ) ntfs_alloc( ins_len + 1 );
|
*outs = ( char * ) ntfs_alloc( ins_len + 1 );
|
||||||
if (!*outs) {
|
if ( !*outs )
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < ins_len; i++) {
|
for ( i = 0; i < ins_len; i++ )
|
||||||
|
{
|
||||||
ntfschar uc = le16_to_cpu( ins[i] );
|
ntfschar uc = le16_to_cpu( ins[i] );
|
||||||
if ( uc > 0xff )
|
if ( uc > 0xff )
|
||||||
uc = ( ntfschar )'_';
|
uc = ( ntfschar )'_';
|
||||||
|
@ -69,7 +69,8 @@ struct _ntfs_dir_state;
|
|||||||
/**
|
/**
|
||||||
* PRIMARY_PARTITION - Block device partition record
|
* PRIMARY_PARTITION - Block device partition record
|
||||||
*/
|
*/
|
||||||
typedef struct _PARTITION_RECORD {
|
typedef struct _PARTITION_RECORD
|
||||||
|
{
|
||||||
u8 status; /* Partition status; see above */
|
u8 status; /* Partition status; see above */
|
||||||
u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */
|
u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */
|
||||||
u8 type; /* Partition type; see above */
|
u8 type; /* Partition type; see above */
|
||||||
@ -81,7 +82,8 @@ typedef struct _PARTITION_RECORD {
|
|||||||
/**
|
/**
|
||||||
* MASTER_BOOT_RECORD - Block device master boot record
|
* MASTER_BOOT_RECORD - Block device master boot record
|
||||||
*/
|
*/
|
||||||
typedef struct _MASTER_BOOT_RECORD {
|
typedef struct _MASTER_BOOT_RECORD
|
||||||
|
{
|
||||||
u8 code_area[446]; /* Code area; normally empty */
|
u8 code_area[446]; /* Code area; normally empty */
|
||||||
PARTITION_RECORD partitions[4]; /* 4 primary partitions */
|
PARTITION_RECORD partitions[4]; /* 4 primary partitions */
|
||||||
u16 signature; /* MBR signature; 0xAA55 */
|
u16 signature; /* MBR signature; 0xAA55 */
|
||||||
@ -90,7 +92,8 @@ typedef struct _MASTER_BOOT_RECORD {
|
|||||||
/**
|
/**
|
||||||
* EXTENDED_PARTITION - Block device extended boot record
|
* EXTENDED_PARTITION - Block device extended boot record
|
||||||
*/
|
*/
|
||||||
typedef struct _EXTENDED_BOOT_RECORD {
|
typedef struct _EXTENDED_BOOT_RECORD
|
||||||
|
{
|
||||||
u8 code_area[446]; /* Code area; normally empty */
|
u8 code_area[446]; /* Code area; normally empty */
|
||||||
PARTITION_RECORD partition; /* Primary partition */
|
PARTITION_RECORD partition; /* Primary partition */
|
||||||
PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */
|
PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */
|
||||||
@ -101,7 +104,8 @@ typedef struct _EXTENDED_BOOT_RECORD {
|
|||||||
/**
|
/**
|
||||||
* INTERFACE_ID - Disc interface identifier
|
* INTERFACE_ID - Disc interface identifier
|
||||||
*/
|
*/
|
||||||
typedef struct _INTERFACE_ID {
|
typedef struct _INTERFACE_ID
|
||||||
|
{
|
||||||
const char *name; /* Interface name */
|
const char *name; /* Interface name */
|
||||||
const DISC_INTERFACE *interface; /* Disc interface */
|
const DISC_INTERFACE *interface; /* Disc interface */
|
||||||
} INTERFACE_ID;
|
} INTERFACE_ID;
|
||||||
@ -109,7 +113,8 @@ typedef struct _INTERFACE_ID {
|
|||||||
/**
|
/**
|
||||||
* ntfs_atime_t - File access time update strategies
|
* ntfs_atime_t - File access time update strategies
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ATIME_ENABLED, /* Update access times */
|
ATIME_ENABLED, /* Update access times */
|
||||||
ATIME_DISABLED /* Don't update access times */
|
ATIME_DISABLED /* Don't update access times */
|
||||||
} ntfs_atime_t;
|
} ntfs_atime_t;
|
||||||
@ -117,7 +122,8 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* ntfs_vd - NTFS volume descriptor
|
* ntfs_vd - NTFS volume descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_vd {
|
typedef struct _ntfs_vd
|
||||||
|
{
|
||||||
struct ntfs_device *dev; /* NTFS device handle */
|
struct ntfs_device *dev; /* NTFS device handle */
|
||||||
ntfs_volume *vol; /* NTFS volume handle */
|
ntfs_volume *vol; /* NTFS volume handle */
|
||||||
mutex_t lock; /* Volume lock mutex */
|
mutex_t lock; /* Volume lock mutex */
|
||||||
|
@ -106,25 +106,29 @@
|
|||||||
* ---------------------- end from RFC 4122 -----------------------
|
* ---------------------- end from RFC 4122 -----------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
GUID object_id;
|
GUID object_id;
|
||||||
} OBJECT_ID_INDEX_KEY;
|
} OBJECT_ID_INDEX_KEY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
le64 file_id;
|
le64 file_id;
|
||||||
GUID birth_volume_id;
|
GUID birth_volume_id;
|
||||||
GUID birth_object_id;
|
GUID birth_object_id;
|
||||||
GUID domain_id;
|
GUID domain_id;
|
||||||
} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
|
} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
|
||||||
|
|
||||||
struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */
|
struct OBJECT_ID_INDEX /* index entry in $Extend/$ObjId */
|
||||||
|
{
|
||||||
INDEX_ENTRY_HEADER header;
|
INDEX_ENTRY_HEADER header;
|
||||||
OBJECT_ID_INDEX_KEY key;
|
OBJECT_ID_INDEX_KEY key;
|
||||||
OBJECT_ID_INDEX_DATA data;
|
OBJECT_ID_INDEX_DATA data;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
static ntfschar objid_index_name[] = { const_cpu_to_le16( '$' ),
|
static ntfschar objid_index_name[] = { const_cpu_to_le16( '$' ),
|
||||||
const_cpu_to_le16('O') };
|
const_cpu_to_le16( 'O' )
|
||||||
|
};
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -192,18 +196,22 @@ static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
|
|||||||
/* do not use path_name_to inode - could reopen root */
|
/* do not use path_name_to inode - could reopen root */
|
||||||
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
||||||
ni = ( ntfs_inode* )NULL;
|
ni = ( ntfs_inode* )NULL;
|
||||||
if (dir_ni) {
|
if ( dir_ni )
|
||||||
|
{
|
||||||
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$ObjId" );
|
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$ObjId" );
|
||||||
if ( inum != ( u64 ) - 1 )
|
if ( inum != ( u64 ) - 1 )
|
||||||
ni = ntfs_inode_open( vol, inum );
|
ni = ntfs_inode_open( vol, inum );
|
||||||
ntfs_inode_close( dir_ni );
|
ntfs_inode_close( dir_ni );
|
||||||
}
|
}
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
xo = ntfs_index_ctx_get( ni, objid_index_name, 2 );
|
xo = ntfs_index_ctx_get( ni, objid_index_name, 2 );
|
||||||
if (!xo) {
|
if ( !xo )
|
||||||
|
{
|
||||||
ntfs_inode_close( ni );
|
ntfs_inode_close( ni );
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
xo = ( ntfs_index_context* )NULL;
|
xo = ( ntfs_index_context* )NULL;
|
||||||
return ( xo );
|
return ( xo );
|
||||||
}
|
}
|
||||||
@ -230,15 +238,18 @@ static int merge_index_data(ntfs_inode *ni,
|
|||||||
|
|
||||||
res = -1;
|
res = -1;
|
||||||
xo = open_object_id_index( ni->vol );
|
xo = open_object_id_index( ni->vol );
|
||||||
if (xo) {
|
if ( xo )
|
||||||
|
{
|
||||||
memcpy( &key.object_id, objectid_attr, sizeof( GUID ) );
|
memcpy( &key.object_id, objectid_attr, sizeof( GUID ) );
|
||||||
if ( !ntfs_index_lookup( &key,
|
if ( !ntfs_index_lookup( &key,
|
||||||
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
||||||
|
{
|
||||||
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
||||||
/* make sure inode numbers match */
|
/* make sure inode numbers match */
|
||||||
if ( entry
|
if ( entry
|
||||||
&& ( MREF( le64_to_cpu( entry->data.file_id ) )
|
&& ( MREF( le64_to_cpu( entry->data.file_id ) )
|
||||||
== ni->mft_no)) {
|
== ni->mft_no ) )
|
||||||
|
{
|
||||||
memcpy( &full_objectid->birth_volume_id,
|
memcpy( &full_objectid->birth_volume_id,
|
||||||
&entry->data.birth_volume_id,
|
&entry->data.birth_volume_id,
|
||||||
sizeof( GUID ) );
|
sizeof( GUID ) );
|
||||||
@ -277,15 +288,18 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = na->data_size;
|
ret = na->data_size;
|
||||||
if (ret) {
|
if ( ret )
|
||||||
|
{
|
||||||
/* read the existing object id attribute */
|
/* read the existing object id attribute */
|
||||||
size = ntfs_attr_pread( na, 0, sizeof( GUID ), old_attr );
|
size = ntfs_attr_pread( na, 0, sizeof( GUID ), old_attr );
|
||||||
if (size >= (s64)sizeof(GUID)) {
|
if ( size >= ( s64 )sizeof( GUID ) )
|
||||||
|
{
|
||||||
memcpy( &key.object_id,
|
memcpy( &key.object_id,
|
||||||
&old_attr->object_id, sizeof( GUID ) );
|
&old_attr->object_id, sizeof( GUID ) );
|
||||||
size = sizeof( GUID );
|
size = sizeof( GUID );
|
||||||
if ( !ntfs_index_lookup( &key,
|
if ( !ntfs_index_lookup( &key,
|
||||||
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
||||||
|
{
|
||||||
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
||||||
memcpy( &old_attr->birth_volume_id,
|
memcpy( &old_attr->birth_volume_id,
|
||||||
&entry->data.birth_volume_id,
|
&entry->data.birth_volume_id,
|
||||||
@ -300,7 +314,9 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
|
|||||||
if ( ntfs_index_rm( xo ) )
|
if ( ntfs_index_rm( xo ) )
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
}
|
}
|
||||||
@ -335,21 +351,25 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
|
|||||||
res = 0;
|
res = 0;
|
||||||
|
|
||||||
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
|
|
||||||
/* remove the existing index entry */
|
/* remove the existing index entry */
|
||||||
oldsize = remove_object_id_index( na, xo, &old_attr );
|
oldsize = remove_object_id_index( na, xo, &old_attr );
|
||||||
if ( oldsize < 0 )
|
if ( oldsize < 0 )
|
||||||
res = -1;
|
res = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* resize attribute */
|
/* resize attribute */
|
||||||
res = ntfs_attr_truncate( na, ( s64 )sizeof( GUID ) );
|
res = ntfs_attr_truncate( na, ( s64 )sizeof( GUID ) );
|
||||||
/* write the object_id in attribute */
|
/* write the object_id in attribute */
|
||||||
if (!res && value) {
|
if ( !res && value )
|
||||||
|
{
|
||||||
written = ( int )ntfs_attr_pwrite( na,
|
written = ( int )ntfs_attr_pwrite( na,
|
||||||
( s64 )0, ( s64 )sizeof( GUID ),
|
( s64 )0, ( s64 )sizeof( GUID ),
|
||||||
&value->object_id );
|
&value->object_id );
|
||||||
if (written != (s64)sizeof(GUID)) {
|
if ( written != ( s64 )sizeof( GUID ) )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to update "
|
ntfs_log_error( "Failed to update "
|
||||||
"object id\n" );
|
"object id\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -359,7 +379,8 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
|
|||||||
/* write index part if provided */
|
/* write index part if provided */
|
||||||
if ( !res
|
if ( !res
|
||||||
&& ( ( size < sizeof( OBJECT_ID_ATTR ) )
|
&& ( ( size < sizeof( OBJECT_ID_ATTR ) )
|
||||||
|| set_object_id_index(ni,xo,value))) {
|
|| set_object_id_index( ni, xo, value ) ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If cannot index, try to remove the object
|
* If cannot index, try to remove the object
|
||||||
* id and log the error. There will be an
|
* id and log the error. There will be an
|
||||||
@ -372,7 +393,8 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
|
|||||||
}
|
}
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty( ni );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res = -1;
|
res = -1;
|
||||||
return ( res );
|
return ( res );
|
||||||
}
|
}
|
||||||
@ -390,22 +412,29 @@ static int add_object_id(ntfs_inode *ni, int flags)
|
|||||||
u8 dummy;
|
u8 dummy;
|
||||||
|
|
||||||
res = -1; /* default return */
|
res = -1; /* default return */
|
||||||
if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) {
|
if ( !ntfs_attr_exist( ni, AT_OBJECT_ID, AT_UNNAMED, 0 ) )
|
||||||
if (!(flags & XATTR_REPLACE)) {
|
{
|
||||||
|
if ( !( flags & XATTR_REPLACE ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* no object id attribute : add one,
|
* no object id attribute : add one,
|
||||||
* apparently, this does not feed the new value in
|
* apparently, this does not feed the new value in
|
||||||
* Note : NTFS version must be >= 3
|
* Note : NTFS version must be >= 3
|
||||||
*/
|
*/
|
||||||
if (ni->vol->major_ver >= 3) {
|
if ( ni->vol->major_ver >= 3 )
|
||||||
|
{
|
||||||
res = ntfs_attr_add( ni, AT_OBJECT_ID,
|
res = ntfs_attr_add( ni, AT_OBJECT_ID,
|
||||||
AT_UNNAMED, 0, &dummy, ( s64 )0 );
|
AT_UNNAMED, 0, &dummy, ( s64 )0 );
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty( ni );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( flags & XATTR_CREATE )
|
if ( flags & XATTR_CREATE )
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
else
|
else
|
||||||
@ -433,13 +462,15 @@ int ntfs_delete_object_id_index(ntfs_inode *ni)
|
|||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* read the existing object id
|
* read the existing object id
|
||||||
* and un-index it
|
* and un-index it
|
||||||
*/
|
*/
|
||||||
xo = open_object_id_index( ni->vol );
|
xo = open_object_id_index( ni->vol );
|
||||||
if (xo) {
|
if ( xo )
|
||||||
|
{
|
||||||
if ( remove_object_id_index( na, xo, &old_attr ) < 0 )
|
if ( remove_object_id_index( na, xo, &old_attr ) < 0 )
|
||||||
res = -1;
|
res = -1;
|
||||||
xoni = xo->ni;
|
xoni = xo->ni;
|
||||||
@ -473,34 +504,42 @@ int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size)
|
|||||||
int full_size;
|
int full_size;
|
||||||
|
|
||||||
full_size = 0; /* default to no data and some error to be defined */
|
full_size = 0; /* default to no data and some error to be defined */
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
objectid_attr = ( OBJECT_ID_ATTR* )ntfs_attr_readall( ni,
|
objectid_attr = ( OBJECT_ID_ATTR* )ntfs_attr_readall( ni,
|
||||||
AT_OBJECT_ID, ( ntfschar* )NULL, 0, &attr_size );
|
AT_OBJECT_ID, ( ntfschar* )NULL, 0, &attr_size );
|
||||||
if (objectid_attr) {
|
if ( objectid_attr )
|
||||||
|
{
|
||||||
/* restrict to only GUID present in attr */
|
/* restrict to only GUID present in attr */
|
||||||
if (attr_size == sizeof(GUID)) {
|
if ( attr_size == sizeof( GUID ) )
|
||||||
|
{
|
||||||
memcpy( &full_objectid.object_id,
|
memcpy( &full_objectid.object_id,
|
||||||
objectid_attr, sizeof( GUID ) );
|
objectid_attr, sizeof( GUID ) );
|
||||||
full_size = sizeof( GUID );
|
full_size = sizeof( GUID );
|
||||||
/* get data from index, if any */
|
/* get data from index, if any */
|
||||||
if ( !merge_index_data( ni, objectid_attr,
|
if ( !merge_index_data( ni, objectid_attr,
|
||||||
&full_objectid)) {
|
&full_objectid ) )
|
||||||
|
{
|
||||||
full_size = sizeof( OBJECT_ID_ATTR );
|
full_size = sizeof( OBJECT_ID_ATTR );
|
||||||
}
|
}
|
||||||
if (full_size <= (s64)size) {
|
if ( full_size <= ( s64 )size )
|
||||||
|
{
|
||||||
if ( value )
|
if ( value )
|
||||||
memcpy( value, &full_objectid,
|
memcpy( value, &full_objectid,
|
||||||
full_size );
|
full_size );
|
||||||
else
|
else
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* unexpected size, better return unsupported */
|
/* unexpected size, better return unsupported */
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
full_size = 0;
|
full_size = 0;
|
||||||
}
|
}
|
||||||
free( objectid_attr );
|
free( objectid_attr );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
}
|
}
|
||||||
return ( full_size ? ( int )full_size : -errno );
|
return ( full_size ? ( int )full_size : -errno );
|
||||||
@ -525,22 +564,28 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni,
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if (ni && value && (size >= sizeof(GUID))) {
|
if ( ni && value && ( size >= sizeof( GUID ) ) )
|
||||||
|
{
|
||||||
xo = open_object_id_index( ni->vol );
|
xo = open_object_id_index( ni->vol );
|
||||||
if (xo) {
|
if ( xo )
|
||||||
|
{
|
||||||
/* make sure the GUID was not used somewhere */
|
/* make sure the GUID was not used somewhere */
|
||||||
memcpy( &key.object_id, value, sizeof( GUID ) );
|
memcpy( &key.object_id, value, sizeof( GUID ) );
|
||||||
if ( ntfs_index_lookup( &key,
|
if ( ntfs_index_lookup( &key,
|
||||||
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
||||||
|
{
|
||||||
ntfs_index_ctx_reinit( xo );
|
ntfs_index_ctx_reinit( xo );
|
||||||
res = add_object_id( ni, flags );
|
res = add_object_id( ni, flags );
|
||||||
if (!res) {
|
if ( !res )
|
||||||
|
{
|
||||||
/* update value and index */
|
/* update value and index */
|
||||||
res = update_object_id( ni, xo,
|
res = update_object_id( ni, xo,
|
||||||
( const OBJECT_ID_ATTR* )value,
|
( const OBJECT_ID_ATTR* )value,
|
||||||
size );
|
size );
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* GUID is present elsewhere */
|
/* GUID is present elsewhere */
|
||||||
res = -1;
|
res = -1;
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
@ -550,10 +595,14 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni,
|
|||||||
NInoSetDirty( xoni );
|
NInoSetDirty( xoni );
|
||||||
ntfs_index_ctx_put( xo );
|
ntfs_index_ctx_put( xo );
|
||||||
ntfs_inode_close( xoni );
|
ntfs_inode_close( xoni );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
@ -577,25 +626,32 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
|
|||||||
OBJECT_ID_ATTR old_attr;
|
OBJECT_ID_ATTR old_attr;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* open and delete the object id
|
* open and delete the object id
|
||||||
*/
|
*/
|
||||||
na = ntfs_attr_open( ni, AT_OBJECT_ID,
|
na = ntfs_attr_open( ni, AT_OBJECT_ID,
|
||||||
AT_UNNAMED, 0 );
|
AT_UNNAMED, 0 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
/* first remove index (old object id needed) */
|
/* first remove index (old object id needed) */
|
||||||
xo = open_object_id_index( ni->vol );
|
xo = open_object_id_index( ni->vol );
|
||||||
if (xo) {
|
if ( xo )
|
||||||
|
{
|
||||||
oldsize = remove_object_id_index( na, xo,
|
oldsize = remove_object_id_index( na, xo,
|
||||||
&old_attr );
|
&old_attr );
|
||||||
if (oldsize < 0) {
|
if ( oldsize < 0 )
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* now remove attribute */
|
/* now remove attribute */
|
||||||
res = ntfs_attr_rm( na );
|
res = ntfs_attr_rm( na );
|
||||||
if ( res
|
if ( res
|
||||||
&& (oldsize > (int)sizeof(GUID))) {
|
&& ( oldsize > ( int )sizeof( GUID ) ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If we could not remove the
|
* If we could not remove the
|
||||||
* attribute, try to restore the
|
* attribute, try to restore the
|
||||||
@ -622,12 +678,16 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
|
|||||||
/* avoid errno pollution */
|
/* avoid errno pollution */
|
||||||
if ( errno == ENOENT )
|
if ( errno == ENOENT )
|
||||||
errno = olderrno;
|
errno = olderrno;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty( ni );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
|
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
|
||||||
|
|
||||||
/* default security sub-authorities */
|
/* default security sub-authorities */
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
||||||
DEFSECAUTH2 = 589793238,
|
DEFSECAUTH2 = 589793238,
|
||||||
DEFSECAUTH3 = 462843383,
|
DEFSECAUTH3 = 462843383,
|
||||||
|
@ -71,7 +71,8 @@
|
|||||||
#define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007)
|
#define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007)
|
||||||
#define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C)
|
#define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C)
|
||||||
|
|
||||||
struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */
|
struct MOUNT_POINT_REPARSE_DATA /* reparse data for junctions */
|
||||||
|
{
|
||||||
le16 subst_name_offset;
|
le16 subst_name_offset;
|
||||||
le16 subst_name_length;
|
le16 subst_name_length;
|
||||||
le16 print_name_offset;
|
le16 print_name_offset;
|
||||||
@ -79,7 +80,8 @@ struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */
|
|||||||
char path_buffer[0]; /* above data assume this is char array */
|
char path_buffer[0]; /* above data assume this is char array */
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct SYMLINK_REPARSE_DATA { /* reparse data for symlinks */
|
struct SYMLINK_REPARSE_DATA /* reparse data for symlinks */
|
||||||
|
{
|
||||||
le16 subst_name_offset;
|
le16 subst_name_offset;
|
||||||
le16 subst_name_length;
|
le16 subst_name_length;
|
||||||
le16 print_name_offset;
|
le16 print_name_offset;
|
||||||
@ -88,20 +90,23 @@ struct SYMLINK_REPARSE_DATA { /* reparse data for symlinks */
|
|||||||
char path_buffer[0]; /* above data assume this is char array */
|
char path_buffer[0]; /* above data assume this is char array */
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct REPARSE_INDEX { /* index entry in $Extend/$Reparse */
|
struct REPARSE_INDEX /* index entry in $Extend/$Reparse */
|
||||||
|
{
|
||||||
INDEX_ENTRY_HEADER header;
|
INDEX_ENTRY_HEADER header;
|
||||||
REPARSE_INDEX_KEY key;
|
REPARSE_INDEX_KEY key;
|
||||||
le32 filling;
|
le32 filling;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
static const ntfschar dir_junction_head[] = {
|
static const ntfschar dir_junction_head[] =
|
||||||
|
{
|
||||||
const_cpu_to_le16( '\\' ),
|
const_cpu_to_le16( '\\' ),
|
||||||
const_cpu_to_le16( '?' ),
|
const_cpu_to_le16( '?' ),
|
||||||
const_cpu_to_le16( '?' ),
|
const_cpu_to_le16( '?' ),
|
||||||
const_cpu_to_le16( '\\' )
|
const_cpu_to_le16( '\\' )
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
static const ntfschar vol_junction_head[] = {
|
static const ntfschar vol_junction_head[] =
|
||||||
|
{
|
||||||
const_cpu_to_le16( '\\' ),
|
const_cpu_to_le16( '\\' ),
|
||||||
const_cpu_to_le16( '?' ),
|
const_cpu_to_le16( '?' ),
|
||||||
const_cpu_to_le16( '?' ),
|
const_cpu_to_le16( '?' ),
|
||||||
@ -116,7 +121,8 @@ static const ntfschar vol_junction_head[] = {
|
|||||||
} ;
|
} ;
|
||||||
|
|
||||||
static ntfschar reparse_index_name[] = { const_cpu_to_le16( '$' ),
|
static ntfschar reparse_index_name[] = { const_cpu_to_le16( '$' ),
|
||||||
const_cpu_to_le16('R') };
|
const_cpu_to_le16( 'R' )
|
||||||
|
};
|
||||||
|
|
||||||
static const char mappingdir[] = ".NTFS-3G/";
|
static const char mappingdir[] = ".NTFS-3G/";
|
||||||
|
|
||||||
@ -146,18 +152,21 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
|
|||||||
u32 cpuchar;
|
u32 cpuchar;
|
||||||
INDEX_ENTRY *entry;
|
INDEX_ENTRY *entry;
|
||||||
FILE_NAME_ATTR *found;
|
FILE_NAME_ATTR *found;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
FILE_NAME_ATTR attr;
|
FILE_NAME_ATTR attr;
|
||||||
ntfschar file_name[NTFS_MAX_NAME_LEN + 1];
|
ntfschar file_name[NTFS_MAX_NAME_LEN + 1];
|
||||||
} find;
|
} find;
|
||||||
|
|
||||||
mref = ( u64 ) - 1; /* default return (not found) */
|
mref = ( u64 ) - 1; /* default return (not found) */
|
||||||
icx = ntfs_index_ctx_get( dir_ni, NTFS_INDEX_I30, 4 );
|
icx = ntfs_index_ctx_get( dir_ni, NTFS_INDEX_I30, 4 );
|
||||||
if (icx) {
|
if ( icx )
|
||||||
|
{
|
||||||
if ( uname_len > NTFS_MAX_NAME_LEN )
|
if ( uname_len > NTFS_MAX_NAME_LEN )
|
||||||
uname_len = NTFS_MAX_NAME_LEN;
|
uname_len = NTFS_MAX_NAME_LEN;
|
||||||
find.attr.file_name_length = uname_len;
|
find.attr.file_name_length = uname_len;
|
||||||
for (i=0; i<uname_len; i++) {
|
for ( i = 0; i < uname_len; i++ )
|
||||||
|
{
|
||||||
cpuchar = le16_to_cpu( uname[i] );
|
cpuchar = le16_to_cpu( uname[i] );
|
||||||
/*
|
/*
|
||||||
* We need upper or lower value, whichever is smaller,
|
* We need upper or lower value, whichever is smaller,
|
||||||
@ -184,7 +193,8 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
|
|||||||
entry = ntfs_index_next( icx->entry, icx );
|
entry = ntfs_index_next( icx->entry, icx );
|
||||||
else
|
else
|
||||||
entry = icx->entry;
|
entry = icx->entry;
|
||||||
if (entry) {
|
if ( entry )
|
||||||
|
{
|
||||||
found = &entry->key.file_name;
|
found = &entry->key.file_name;
|
||||||
if ( lkup
|
if ( lkup
|
||||||
&& ntfs_names_are_equal( find.attr.file_name,
|
&& ntfs_names_are_equal( find.attr.file_name,
|
||||||
@ -193,7 +203,8 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
|
|||||||
IGNORE_CASE,
|
IGNORE_CASE,
|
||||||
vol->upcase, vol->upcase_len ) )
|
vol->upcase, vol->upcase_len ) )
|
||||||
lkup = 0;
|
lkup = 0;
|
||||||
if (!lkup) {
|
if ( !lkup )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* name found :
|
* name found :
|
||||||
* fix original name and return inode
|
* fix original name and return inode
|
||||||
@ -228,9 +239,11 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
|
|||||||
|
|
||||||
target = ( char* )NULL; /* default return */
|
target = ( char* )NULL; /* default return */
|
||||||
ni = ntfs_inode_open( vol, ( MFT_REF )FILE_root );
|
ni = ntfs_inode_open( vol, ( MFT_REF )FILE_root );
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
start = 0;
|
start = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
len = 0;
|
len = 0;
|
||||||
while ( ( ( start + len ) < count )
|
while ( ( ( start + len ) < count )
|
||||||
&& ( path[start + len] != const_cpu_to_le16( '\\' ) ) )
|
&& ( path[start + len] != const_cpu_to_le16( '\\' ) ) )
|
||||||
@ -238,20 +251,24 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
|
|||||||
inum = ntfs_fix_file_name( ni, &path[start], len );
|
inum = ntfs_fix_file_name( ni, &path[start], len );
|
||||||
ntfs_inode_close( ni );
|
ntfs_inode_close( ni );
|
||||||
ni = ( ntfs_inode* )NULL;
|
ni = ( ntfs_inode* )NULL;
|
||||||
if (inum != (u64)-1) {
|
if ( inum != ( u64 ) - 1 )
|
||||||
|
{
|
||||||
inum = MREF( inum );
|
inum = MREF( inum );
|
||||||
ni = ntfs_inode_open( vol, inum );
|
ni = ntfs_inode_open( vol, inum );
|
||||||
start += len;
|
start += len;
|
||||||
if ( start < count )
|
if ( start < count )
|
||||||
path[start++] = const_cpu_to_le16( '/' );
|
path[start++] = const_cpu_to_le16( '/' );
|
||||||
}
|
}
|
||||||
} while (ni
|
}
|
||||||
|
while ( ni
|
||||||
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
|
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
|
||||||
&& ( start < count ) );
|
&& ( start < count ) );
|
||||||
if ( ni
|
if ( ni
|
||||||
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir ) )
|
&& ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir ) )
|
||||||
if (ntfs_ucstombs(path, count, &target, 0) < 0) {
|
if ( ntfs_ucstombs( path, count, &target, 0 ) < 0 )
|
||||||
if (target) {
|
{
|
||||||
|
if ( target )
|
||||||
|
{
|
||||||
free( target );
|
free( target );
|
||||||
target = ( char* )NULL;
|
target = ( char* )NULL;
|
||||||
}
|
}
|
||||||
@ -288,17 +305,22 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
|||||||
pos = 0;
|
pos = 0;
|
||||||
ok = TRUE;
|
ok = TRUE;
|
||||||
curni = ntfs_dir_parent_inode( ni );
|
curni = ntfs_dir_parent_inode( ni );
|
||||||
while (curni && ok && (pos < (count - 1)) && --max) {
|
while ( curni && ok && ( pos < ( count - 1 ) ) && --max )
|
||||||
|
{
|
||||||
if ( ( count >= ( pos + 2 ) )
|
if ( ( count >= ( pos + 2 ) )
|
||||||
&& ( path[pos] == const_cpu_to_le16( '.' ) )
|
&& ( path[pos] == const_cpu_to_le16( '.' ) )
|
||||||
&& (path[pos+1] == const_cpu_to_le16('\\'))) {
|
&& ( path[pos+1] == const_cpu_to_le16( '\\' ) ) )
|
||||||
|
{
|
||||||
path[1] = const_cpu_to_le16( '/' );
|
path[1] = const_cpu_to_le16( '/' );
|
||||||
pos += 2;
|
pos += 2;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( ( count >= ( pos + 3 ) )
|
if ( ( count >= ( pos + 3 ) )
|
||||||
&& ( path[pos] == const_cpu_to_le16( '.' ) )
|
&& ( path[pos] == const_cpu_to_le16( '.' ) )
|
||||||
&& ( path[pos+1] == const_cpu_to_le16( '.' ) )
|
&& ( path[pos+1] == const_cpu_to_le16( '.' ) )
|
||||||
&& (path[pos+2] == const_cpu_to_le16('\\'))) {
|
&& ( path[pos+2] == const_cpu_to_le16( '\\' ) ) )
|
||||||
|
{
|
||||||
path[2] = const_cpu_to_le16( '/' );
|
path[2] = const_cpu_to_le16( '/' );
|
||||||
pos += 3;
|
pos += 3;
|
||||||
newni = ntfs_dir_parent_inode( curni );
|
newni = ntfs_dir_parent_inode( curni );
|
||||||
@ -307,7 +329,9 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
|||||||
curni = newni;
|
curni = newni;
|
||||||
if ( !curni )
|
if ( !curni )
|
||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
lth = 0;
|
lth = 0;
|
||||||
while ( ( ( pos + lth ) < count )
|
while ( ( ( pos + lth ) < count )
|
||||||
&& ( path[pos + lth] != const_cpu_to_le16( '\\' ) ) )
|
&& ( path[pos + lth] != const_cpu_to_le16( '\\' ) ) )
|
||||||
@ -321,15 +345,20 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
|||||||
&& ntfs_inode_close( curni ) )
|
&& ntfs_inode_close( curni ) )
|
||||||
|| ( inum == ( u64 ) - 1 ) )
|
|| ( inum == ( u64 ) - 1 ) )
|
||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
curni = ntfs_inode_open( ni->vol, MREF( inum ) );
|
curni = ntfs_inode_open( ni->vol, MREF( inum ) );
|
||||||
if ( !curni )
|
if ( !curni )
|
||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
else {
|
else
|
||||||
if (ok && ((pos + lth) < count)) {
|
{
|
||||||
|
if ( ok && ( ( pos + lth ) < count ) )
|
||||||
|
{
|
||||||
path[pos + lth] = const_cpu_to_le16( '/' );
|
path[pos + lth] = const_cpu_to_le16( '/' );
|
||||||
pos += lth + 1;
|
pos += lth + 1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pos += lth;
|
pos += lth;
|
||||||
if ( ( ni->mrec->flags ^ curni->mrec->flags )
|
if ( ( ni->mrec->flags ^ curni->mrec->flags )
|
||||||
& MFT_RECORD_IS_DIRECTORY )
|
& MFT_RECORD_IS_DIRECTORY )
|
||||||
@ -343,7 +372,8 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok && (ntfs_ucstombs(path, count, &target, 0) < 0)) {
|
if ( ok && ( ntfs_ucstombs( path, count, &target, 0 ) < 0 ) )
|
||||||
|
{
|
||||||
free( target ); // needed ?
|
free( target ); // needed ?
|
||||||
target = ( char* )NULL;
|
target = ( char* )NULL;
|
||||||
}
|
}
|
||||||
@ -370,7 +400,8 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
drive = ( char* )NULL;
|
drive = ( char* )NULL;
|
||||||
sz = ntfs_ucstombs( &letter, 1, &drive, 0 );
|
sz = ntfs_ucstombs( &letter, 1, &drive, 0 );
|
||||||
if (sz > 0) {
|
if ( sz > 0 )
|
||||||
|
{
|
||||||
strcpy( defines, mappingdir );
|
strcpy( defines, mappingdir );
|
||||||
if ( ( *drive >= 'a' ) && ( *drive <= 'z' ) )
|
if ( ( *drive >= 'a' ) && ( *drive <= 'z' ) )
|
||||||
*drive += 'A' - 'a';
|
*drive += 'A' - 'a';
|
||||||
@ -380,8 +411,8 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
|
|||||||
ni = ntfs_pathname_to_inode( vol, NULL, defines );
|
ni = ntfs_pathname_to_inode( vol, NULL, defines );
|
||||||
if ( ni && !ntfs_inode_close( ni ) )
|
if ( ni && !ntfs_inode_close( ni ) )
|
||||||
ret = 1;
|
ret = 1;
|
||||||
else
|
else if ( errno == ENOENT )
|
||||||
if (errno == ENOENT) {
|
{
|
||||||
ret = 0;
|
ret = 0;
|
||||||
/* avoid errno pollution */
|
/* avoid errno pollution */
|
||||||
errno = olderrno;
|
errno = olderrno;
|
||||||
@ -415,8 +446,10 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
|
|||||||
&& ( size >= sizeof( REPARSE_POINT ) )
|
&& ( size >= sizeof( REPARSE_POINT ) )
|
||||||
&& ( ( ( size_t )le16_to_cpu( reparse_attr->reparse_data_length )
|
&& ( ( ( size_t )le16_to_cpu( reparse_attr->reparse_data_length )
|
||||||
+ sizeof( REPARSE_POINT ) ) == size );
|
+ sizeof( REPARSE_POINT ) ) == size );
|
||||||
if (ok) {
|
if ( ok )
|
||||||
switch (reparse_attr->reparse_tag) {
|
{
|
||||||
|
switch ( reparse_attr->reparse_tag )
|
||||||
|
{
|
||||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||||
mount_point_data = ( const struct MOUNT_POINT_REPARSE_DATA* )
|
mount_point_data = ( const struct MOUNT_POINT_REPARSE_DATA* )
|
||||||
reparse_attr->reparse_data;
|
reparse_attr->reparse_data;
|
||||||
@ -503,12 +536,15 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
|
|||||||
if ( ( kind == DIR_JUNCTION )
|
if ( ( kind == DIR_JUNCTION )
|
||||||
&& ( count >= 7 )
|
&& ( count >= 7 )
|
||||||
&& junction[7]
|
&& junction[7]
|
||||||
&& !ntfs_drive_letter(vol, junction[4])) {
|
&& !ntfs_drive_letter( vol, junction[4] ) )
|
||||||
|
{
|
||||||
target = search_absolute( vol, &junction[7], count - 7, isdir );
|
target = search_absolute( vol, &junction[7], count - 7, isdir );
|
||||||
if (target) {
|
if ( target )
|
||||||
|
{
|
||||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||||
+ strlen( target ) + 2 );
|
+ strlen( target ) + 2 );
|
||||||
if (fulltarget) {
|
if ( fulltarget )
|
||||||
|
{
|
||||||
strcpy( fulltarget, mnt_point );
|
strcpy( fulltarget, mnt_point );
|
||||||
strcat( fulltarget, "/" );
|
strcat( fulltarget, "/" );
|
||||||
strcat( fulltarget, target );
|
strcat( fulltarget, target );
|
||||||
@ -523,11 +559,13 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
|
|||||||
* define as a symbolic link to the real target
|
* define as a symbolic link to the real target
|
||||||
*/
|
*/
|
||||||
if ( ( ( kind == DIR_JUNCTION ) && !fulltarget )
|
if ( ( ( kind == DIR_JUNCTION ) && !fulltarget )
|
||||||
|| (kind == VOL_JUNCTION)) {
|
|| ( kind == VOL_JUNCTION ) )
|
||||||
|
{
|
||||||
sz = ntfs_ucstombs( &junction[4],
|
sz = ntfs_ucstombs( &junction[4],
|
||||||
( kind == VOL_JUNCTION ? count - 5 : count - 4 ),
|
( kind == VOL_JUNCTION ? count - 5 : count - 4 ),
|
||||||
&target, 0 );
|
&target, 0 );
|
||||||
if ((sz > 0) && target) {
|
if ( ( sz > 0 ) && target )
|
||||||
|
{
|
||||||
/* reverse slashes */
|
/* reverse slashes */
|
||||||
for ( q = target; *q; q++ )
|
for ( q = target; *q; q++ )
|
||||||
if ( *q == '\\' )
|
if ( *q == '\\' )
|
||||||
@ -539,7 +577,8 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
|
|||||||
target[0] += 'A' - 'a';
|
target[0] += 'A' - 'a';
|
||||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||||
+ sizeof( mappingdir ) + strlen( target ) + 1 );
|
+ sizeof( mappingdir ) + strlen( target ) + 1 );
|
||||||
if (fulltarget) {
|
if ( fulltarget )
|
||||||
|
{
|
||||||
strcpy( fulltarget, mnt_point );
|
strcpy( fulltarget, mnt_point );
|
||||||
strcat( fulltarget, "/" );
|
strcat( fulltarget, "/" );
|
||||||
strcat( fulltarget, mappingdir );
|
strcat( fulltarget, mappingdir );
|
||||||
@ -605,17 +644,20 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
|
|||||||
&& ( count >= 3 )
|
&& ( count >= 3 )
|
||||||
&& junction[3]
|
&& junction[3]
|
||||||
&& !ntfs_drive_letter( vol, junction[0] ) )
|
&& !ntfs_drive_letter( vol, junction[0] ) )
|
||||||
|| (kind == ABS_PATH)) {
|
|| ( kind == ABS_PATH ) )
|
||||||
|
{
|
||||||
if ( kind == ABS_PATH )
|
if ( kind == ABS_PATH )
|
||||||
target = search_absolute( vol, &junction[1],
|
target = search_absolute( vol, &junction[1],
|
||||||
count - 1, isdir );
|
count - 1, isdir );
|
||||||
else
|
else
|
||||||
target = search_absolute( vol, &junction[3],
|
target = search_absolute( vol, &junction[3],
|
||||||
count - 3, isdir );
|
count - 3, isdir );
|
||||||
if (target) {
|
if ( target )
|
||||||
|
{
|
||||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||||
+ strlen( target ) + 2 );
|
+ strlen( target ) + 2 );
|
||||||
if (fulltarget) {
|
if ( fulltarget )
|
||||||
|
{
|
||||||
strcpy( fulltarget, mnt_point );
|
strcpy( fulltarget, mnt_point );
|
||||||
strcat( fulltarget, "/" );
|
strcat( fulltarget, "/" );
|
||||||
strcat( fulltarget, target );
|
strcat( fulltarget, target );
|
||||||
@ -628,10 +670,12 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
|
|||||||
* link to /.NTFS-3G/target which the user can
|
* link to /.NTFS-3G/target which the user can
|
||||||
* define as a symbolic link to the real target
|
* define as a symbolic link to the real target
|
||||||
*/
|
*/
|
||||||
if ((kind == FULL_PATH) && !fulltarget) {
|
if ( ( kind == FULL_PATH ) && !fulltarget )
|
||||||
|
{
|
||||||
sz = ntfs_ucstombs( &junction[0],
|
sz = ntfs_ucstombs( &junction[0],
|
||||||
count, &target, 0 );
|
count, &target, 0 );
|
||||||
if ((sz > 0) && target) {
|
if ( ( sz > 0 ) && target )
|
||||||
|
{
|
||||||
/* reverse slashes */
|
/* reverse slashes */
|
||||||
for ( q = target; *q; q++ )
|
for ( q = target; *q; q++ )
|
||||||
if ( *q == '\\' )
|
if ( *q == '\\' )
|
||||||
@ -643,7 +687,8 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
|
|||||||
target[0] += 'A' - 'a';
|
target[0] += 'A' - 'a';
|
||||||
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
fulltarget = ( char* )ntfs_malloc( strlen( mnt_point )
|
||||||
+ sizeof( mappingdir ) + strlen( target ) + 1 );
|
+ sizeof( mappingdir ) + strlen( target ) + 1 );
|
||||||
if (fulltarget) {
|
if ( fulltarget )
|
||||||
|
{
|
||||||
strcpy( fulltarget, mnt_point );
|
strcpy( fulltarget, mnt_point );
|
||||||
strcat( fulltarget, "/" );
|
strcat( fulltarget, "/" );
|
||||||
strcat( fulltarget, mappingdir );
|
strcat( fulltarget, mappingdir );
|
||||||
@ -710,8 +755,10 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
|||||||
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
||||||
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
||||||
if ( reparse_attr && attr_size
|
if ( reparse_attr && attr_size
|
||||||
&& valid_reparse_data(ni, reparse_attr, attr_size)) {
|
&& valid_reparse_data( ni, reparse_attr, attr_size ) )
|
||||||
switch (reparse_attr->reparse_tag) {
|
{
|
||||||
|
switch ( reparse_attr->reparse_tag )
|
||||||
|
{
|
||||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||||
mount_point_data = ( struct MOUNT_POINT_REPARSE_DATA* )
|
mount_point_data = ( struct MOUNT_POINT_REPARSE_DATA* )
|
||||||
reparse_attr->reparse_data;
|
reparse_attr->reparse_data;
|
||||||
@ -734,23 +781,26 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
|||||||
* Predetermine the kind of target,
|
* Predetermine the kind of target,
|
||||||
* the called function has to make a full check
|
* the called function has to make a full check
|
||||||
*/
|
*/
|
||||||
if (*p++ == const_cpu_to_le16('\\')) {
|
if ( *p++ == const_cpu_to_le16( '\\' ) )
|
||||||
|
{
|
||||||
if ( ( *p == const_cpu_to_le16( '?' ) )
|
if ( ( *p == const_cpu_to_le16( '?' ) )
|
||||||
|| ( *p == const_cpu_to_le16( '\\' ) ) )
|
|| ( *p == const_cpu_to_le16( '\\' ) ) )
|
||||||
kind = FULL_TARGET;
|
kind = FULL_TARGET;
|
||||||
else
|
else
|
||||||
kind = ABS_TARGET;
|
kind = ABS_TARGET;
|
||||||
} else
|
}
|
||||||
if (*p == const_cpu_to_le16(':'))
|
else if ( *p == const_cpu_to_le16( ':' ) )
|
||||||
kind = ABS_TARGET;
|
kind = ABS_TARGET;
|
||||||
else
|
else
|
||||||
kind = REL_TARGET;
|
kind = REL_TARGET;
|
||||||
p--;
|
p--;
|
||||||
/* reparse data consistency has been checked */
|
/* reparse data consistency has been checked */
|
||||||
switch (kind) {
|
switch ( kind )
|
||||||
|
{
|
||||||
case FULL_TARGET :
|
case FULL_TARGET :
|
||||||
if ( !( symlink_data->flags
|
if ( !( symlink_data->flags
|
||||||
& const_cpu_to_le32(1))) {
|
& const_cpu_to_le32( 1 ) ) )
|
||||||
|
{
|
||||||
target = ntfs_get_fulllink( vol,
|
target = ntfs_get_fulllink( vol,
|
||||||
p, lth / 2,
|
p, lth / 2,
|
||||||
mnt_point, isdir );
|
mnt_point, isdir );
|
||||||
@ -760,7 +810,8 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
|||||||
break;
|
break;
|
||||||
case ABS_TARGET :
|
case ABS_TARGET :
|
||||||
if ( symlink_data->flags
|
if ( symlink_data->flags
|
||||||
& const_cpu_to_le32(1)) {
|
& const_cpu_to_le32( 1 ) )
|
||||||
|
{
|
||||||
target = ntfs_get_abslink( vol,
|
target = ntfs_get_abslink( vol,
|
||||||
p, lth / 2,
|
p, lth / 2,
|
||||||
mnt_point, isdir );
|
mnt_point, isdir );
|
||||||
@ -770,7 +821,8 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
|||||||
break;
|
break;
|
||||||
case REL_TARGET :
|
case REL_TARGET :
|
||||||
if ( symlink_data->flags
|
if ( symlink_data->flags
|
||||||
& const_cpu_to_le32(1)) {
|
& const_cpu_to_le32( 1 ) )
|
||||||
|
{
|
||||||
target = ntfs_get_rellink( ni,
|
target = ntfs_get_rellink( ni,
|
||||||
p, lth / 2 );
|
p, lth / 2 );
|
||||||
if ( target )
|
if ( target )
|
||||||
@ -805,8 +857,10 @@ BOOL ntfs_possible_symlink(ntfs_inode *ni)
|
|||||||
possible = FALSE;
|
possible = FALSE;
|
||||||
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
||||||
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
||||||
if (reparse_attr && attr_size) {
|
if ( reparse_attr && attr_size )
|
||||||
switch (reparse_attr->reparse_tag) {
|
{
|
||||||
|
switch ( reparse_attr->reparse_tag )
|
||||||
|
{
|
||||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||||
case IO_REPARSE_TAG_SYMLINK :
|
case IO_REPARSE_TAG_SYMLINK :
|
||||||
possible = TRUE;
|
possible = TRUE;
|
||||||
@ -877,10 +931,12 @@ static int remove_reparse_index(ntfs_attr *na, ntfs_index_context *xr,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = na->data_size;
|
ret = na->data_size;
|
||||||
if (ret) {
|
if ( ret )
|
||||||
|
{
|
||||||
/* read the existing reparse_tag */
|
/* read the existing reparse_tag */
|
||||||
size = ntfs_attr_pread( na, 0, 4, preparse_tag );
|
size = ntfs_attr_pread( na, 0, 4, preparse_tag );
|
||||||
if (size == 4) {
|
if ( size == 4 )
|
||||||
|
{
|
||||||
seqn = na->ni->mrec->sequence_number;
|
seqn = na->ni->mrec->sequence_number;
|
||||||
file_id_cpu = MK_MREF( na->ni->mft_no, le16_to_cpu( seqn ) );
|
file_id_cpu = MK_MREF( na->ni->mft_no, le16_to_cpu( seqn ) );
|
||||||
file_id = cpu_to_le64( file_id_cpu );
|
file_id = cpu_to_le64( file_id_cpu );
|
||||||
@ -890,7 +946,9 @@ static int remove_reparse_index(ntfs_attr *na, ntfs_index_context *xr,
|
|||||||
if ( !ntfs_index_lookup( &key, sizeof( REPARSE_INDEX_KEY ), xr )
|
if ( !ntfs_index_lookup( &key, sizeof( REPARSE_INDEX_KEY ), xr )
|
||||||
&& ntfs_index_rm( xr ) )
|
&& ntfs_index_rm( xr ) )
|
||||||
ret = -1;
|
ret = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
}
|
}
|
||||||
@ -917,18 +975,22 @@ static ntfs_index_context *open_reparse_index(ntfs_volume *vol)
|
|||||||
/* do not use path_name_to inode - could reopen root */
|
/* do not use path_name_to inode - could reopen root */
|
||||||
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
||||||
ni = ( ntfs_inode* )NULL;
|
ni = ( ntfs_inode* )NULL;
|
||||||
if (dir_ni) {
|
if ( dir_ni )
|
||||||
|
{
|
||||||
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$Reparse" );
|
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$Reparse" );
|
||||||
if ( inum != ( u64 ) - 1 )
|
if ( inum != ( u64 ) - 1 )
|
||||||
ni = ntfs_inode_open( vol, inum );
|
ni = ntfs_inode_open( vol, inum );
|
||||||
ntfs_inode_close( dir_ni );
|
ntfs_inode_close( dir_ni );
|
||||||
}
|
}
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
xr = ntfs_index_ctx_get( ni, reparse_index_name, 2 );
|
xr = ntfs_index_ctx_get( ni, reparse_index_name, 2 );
|
||||||
if (!xr) {
|
if ( !xr )
|
||||||
|
{
|
||||||
ntfs_inode_close( ni );
|
ntfs_inode_close( ni );
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
xr = ( ntfs_index_context* )NULL;
|
xr = ( ntfs_index_context* )NULL;
|
||||||
return ( xr );
|
return ( xr );
|
||||||
}
|
}
|
||||||
@ -959,19 +1021,23 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
|||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
/* remove the existing reparse data */
|
/* remove the existing reparse data */
|
||||||
oldsize = remove_reparse_index( na, xr, &reparse_tag );
|
oldsize = remove_reparse_index( na, xr, &reparse_tag );
|
||||||
if ( oldsize < 0 )
|
if ( oldsize < 0 )
|
||||||
res = -1;
|
res = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* resize attribute */
|
/* resize attribute */
|
||||||
res = ntfs_attr_truncate( na, ( s64 )size );
|
res = ntfs_attr_truncate( na, ( s64 )size );
|
||||||
/* overwrite value if any */
|
/* overwrite value if any */
|
||||||
if (!res && value) {
|
if ( !res && value )
|
||||||
|
{
|
||||||
written = ( int )ntfs_attr_pwrite( na,
|
written = ( int )ntfs_attr_pwrite( na,
|
||||||
( s64 )0, ( s64 )size, value );
|
( s64 )0, ( s64 )size, value );
|
||||||
if (written != (s64)size) {
|
if ( written != ( s64 )size )
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to update "
|
ntfs_log_error( "Failed to update "
|
||||||
"reparse data\n" );
|
"reparse data\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -981,7 +1047,8 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
|||||||
if ( !res
|
if ( !res
|
||||||
&& set_reparse_index( ni, xr,
|
&& set_reparse_index( ni, xr,
|
||||||
( ( const REPARSE_POINT* )value )->reparse_tag )
|
( ( const REPARSE_POINT* )value )->reparse_tag )
|
||||||
&& (oldsize > 0)) {
|
&& ( oldsize > 0 ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If cannot index, try to remove the reparse
|
* If cannot index, try to remove the reparse
|
||||||
* data and log the error. There will be an
|
* data and log the error. There will be an
|
||||||
@ -994,7 +1061,8 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
|||||||
}
|
}
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty( ni );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res = -1;
|
res = -1;
|
||||||
return ( res );
|
return ( res );
|
||||||
}
|
}
|
||||||
@ -1018,13 +1086,15 @@ int ntfs_delete_reparse_index(ntfs_inode *ni)
|
|||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 );
|
na = ntfs_attr_open( ni, AT_REPARSE_POINT, AT_UNNAMED, 0 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* read the existing reparse data (the tag is enough)
|
* read the existing reparse data (the tag is enough)
|
||||||
* and un-index it
|
* and un-index it
|
||||||
*/
|
*/
|
||||||
xr = open_reparse_index( ni->vol );
|
xr = open_reparse_index( ni->vol );
|
||||||
if (xr) {
|
if ( xr )
|
||||||
|
{
|
||||||
if ( remove_reparse_index( na, xr, &reparse_tag ) < 0 )
|
if ( remove_reparse_index( na, xr, &reparse_tag ) < 0 )
|
||||||
res = -1;
|
res = -1;
|
||||||
xrni = xr->ni;
|
xrni = xr->ni;
|
||||||
@ -1053,12 +1123,16 @@ int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size)
|
|||||||
s64 attr_size;
|
s64 attr_size;
|
||||||
|
|
||||||
attr_size = 0; /* default to no data and no error */
|
attr_size = 0; /* default to no data and no error */
|
||||||
if (ni) {
|
if ( ni )
|
||||||
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
|
{
|
||||||
|
if ( ni->flags & FILE_ATTR_REPARSE_POINT )
|
||||||
|
{
|
||||||
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
reparse_attr = ( REPARSE_POINT* )ntfs_attr_readall( ni,
|
||||||
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
AT_REPARSE_POINT, ( ntfschar* )NULL, 0, &attr_size );
|
||||||
if (reparse_attr) {
|
if ( reparse_attr )
|
||||||
if (attr_size <= (s64)size) {
|
{
|
||||||
|
if ( attr_size <= ( s64 )size )
|
||||||
|
{
|
||||||
if ( value )
|
if ( value )
|
||||||
memcpy( value, reparse_attr,
|
memcpy( value, reparse_attr,
|
||||||
attr_size );
|
attr_size );
|
||||||
@ -1067,7 +1141,8 @@ int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size)
|
|||||||
}
|
}
|
||||||
free( reparse_attr );
|
free( reparse_attr );
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
}
|
}
|
||||||
return ( attr_size ? ( int )attr_size : -errno );
|
return ( attr_size ? ( int )attr_size : -errno );
|
||||||
@ -1090,43 +1165,57 @@ int ntfs_set_ntfs_reparse_data(ntfs_inode *ni,
|
|||||||
ntfs_index_context *xr;
|
ntfs_index_context *xr;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if (ni && valid_reparse_data(ni, (const REPARSE_POINT*)value, size)) {
|
if ( ni && valid_reparse_data( ni, ( const REPARSE_POINT* )value, size ) )
|
||||||
|
{
|
||||||
xr = open_reparse_index( ni->vol );
|
xr = open_reparse_index( ni->vol );
|
||||||
if (xr) {
|
if ( xr )
|
||||||
|
{
|
||||||
if ( !ntfs_attr_exist( ni, AT_REPARSE_POINT,
|
if ( !ntfs_attr_exist( ni, AT_REPARSE_POINT,
|
||||||
AT_UNNAMED,0)) {
|
AT_UNNAMED, 0 ) )
|
||||||
if (!(flags & XATTR_REPLACE)) {
|
{
|
||||||
|
if ( !( flags & XATTR_REPLACE ) )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* no reparse data attribute : add one,
|
* no reparse data attribute : add one,
|
||||||
* apparently, this does not feed the new value in
|
* apparently, this does not feed the new value in
|
||||||
* Note : NTFS version must be >= 3
|
* Note : NTFS version must be >= 3
|
||||||
*/
|
*/
|
||||||
if (ni->vol->major_ver >= 3) {
|
if ( ni->vol->major_ver >= 3 )
|
||||||
|
{
|
||||||
res = ntfs_attr_add( ni,
|
res = ntfs_attr_add( ni,
|
||||||
AT_REPARSE_POINT,
|
AT_REPARSE_POINT,
|
||||||
AT_UNNAMED, 0, &dummy,
|
AT_UNNAMED, 0, &dummy,
|
||||||
( s64 )0 );
|
( s64 )0 );
|
||||||
if (!res) {
|
if ( !res )
|
||||||
|
{
|
||||||
ni->flags |=
|
ni->flags |=
|
||||||
FILE_ATTR_REPARSE_POINT;
|
FILE_ATTR_REPARSE_POINT;
|
||||||
NInoFileNameSetDirty( ni );
|
NInoFileNameSetDirty( ni );
|
||||||
}
|
}
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty( ni );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (flags & XATTR_CREATE) {
|
else
|
||||||
|
{
|
||||||
|
if ( flags & XATTR_CREATE )
|
||||||
|
{
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!res) {
|
if ( !res )
|
||||||
|
{
|
||||||
/* update value and index */
|
/* update value and index */
|
||||||
res = update_reparse_data( ni, xr, value, size );
|
res = update_reparse_data( ni, xr, value, size );
|
||||||
}
|
}
|
||||||
@ -1135,10 +1224,14 @@ int ntfs_set_ntfs_reparse_data(ntfs_inode *ni,
|
|||||||
NInoSetDirty( xrni );
|
NInoSetDirty( xrni );
|
||||||
ntfs_index_ctx_put( xr );
|
ntfs_index_ctx_put( xr );
|
||||||
ntfs_inode_close( xrni );
|
ntfs_inode_close( xrni );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
@ -1161,27 +1254,36 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
|
|||||||
le32 reparse_tag;
|
le32 reparse_tag;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if (ni) {
|
if ( ni )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* open and delete the reparse data
|
* open and delete the reparse data
|
||||||
*/
|
*/
|
||||||
na = ntfs_attr_open( ni, AT_REPARSE_POINT,
|
na = ntfs_attr_open( ni, AT_REPARSE_POINT,
|
||||||
AT_UNNAMED, 0 );
|
AT_UNNAMED, 0 );
|
||||||
if (na) {
|
if ( na )
|
||||||
|
{
|
||||||
/* first remove index (reparse data needed) */
|
/* first remove index (reparse data needed) */
|
||||||
xr = open_reparse_index( ni->vol );
|
xr = open_reparse_index( ni->vol );
|
||||||
if (xr) {
|
if ( xr )
|
||||||
|
{
|
||||||
if ( remove_reparse_index( na, xr,
|
if ( remove_reparse_index( na, xr,
|
||||||
&reparse_tag) < 0) {
|
&reparse_tag ) < 0 )
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* now remove attribute */
|
/* now remove attribute */
|
||||||
res = ntfs_attr_rm( na );
|
res = ntfs_attr_rm( na );
|
||||||
if (!res) {
|
if ( !res )
|
||||||
|
{
|
||||||
ni->flags &=
|
ni->flags &=
|
||||||
~FILE_ATTR_REPARSE_POINT;
|
~FILE_ATTR_REPARSE_POINT;
|
||||||
NInoFileNameSetDirty( ni );
|
NInoFileNameSetDirty( ni );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If we could not remove the
|
* If we could not remove the
|
||||||
* attribute, try to restore the
|
* attribute, try to restore the
|
||||||
@ -1207,12 +1309,16 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
|
|||||||
/* avoid errno pollution */
|
/* avoid errno pollution */
|
||||||
if ( errno == ENOENT )
|
if ( errno == ENOENT )
|
||||||
errno = olderrno;
|
errno = olderrno;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty( ni );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
@ -127,19 +127,24 @@ runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
|
|||||||
int last;
|
int last;
|
||||||
int irl;
|
int irl;
|
||||||
|
|
||||||
if (na->rl && rl) {
|
if ( na->rl && rl )
|
||||||
|
{
|
||||||
irl = ( int )( rl - na->rl );
|
irl = ( int )( rl - na->rl );
|
||||||
last = irl;
|
last = irl;
|
||||||
while ( na->rl[last].length )
|
while ( na->rl[last].length )
|
||||||
last++;
|
last++;
|
||||||
newrl = ntfs_rl_realloc( na->rl, last + 1, last + more_entries + 1 );
|
newrl = ntfs_rl_realloc( na->rl, last + 1, last + more_entries + 1 );
|
||||||
if (!newrl) {
|
if ( !newrl )
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
rl = ( runlist_element* )NULL;
|
rl = ( runlist_element* )NULL;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
na->rl = newrl;
|
na->rl = newrl;
|
||||||
rl = &newrl[irl];
|
rl = &newrl[irl];
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "Cannot extend unmapped runlist" );
|
ntfs_log_error( "Cannot extend unmapped runlist" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
rl = ( runlist_element* )NULL;
|
rl = ( runlist_element* )NULL;
|
||||||
@ -160,7 +165,8 @@ runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
|
|||||||
*/
|
*/
|
||||||
static BOOL ntfs_rl_are_mergeable( runlist_element *dst, runlist_element *src )
|
static BOOL ntfs_rl_are_mergeable( runlist_element *dst, runlist_element *src )
|
||||||
{
|
{
|
||||||
if (!dst || !src) {
|
if ( !dst || !src )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Eeek. ntfs_rl_are_mergeable() invoked with NULL "
|
ntfs_log_debug( "Eeek. ntfs_rl_are_mergeable() invoked with NULL "
|
||||||
"pointer!\n" );
|
"pointer!\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -223,7 +229,8 @@ static runlist_element *ntfs_rl_append(runlist_element *dst, int dsize,
|
|||||||
BOOL right = FALSE; /* Right end of @src needs merging */
|
BOOL right = FALSE; /* Right end of @src needs merging */
|
||||||
int marker; /* End of the inserted runs */
|
int marker; /* End of the inserted runs */
|
||||||
|
|
||||||
if (!dst || !src) {
|
if ( !dst || !src )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Eeek. ntfs_rl_append() invoked with NULL "
|
ntfs_log_debug( "Eeek. ntfs_rl_append() invoked with NULL "
|
||||||
"pointer!\n" );
|
"pointer!\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@ -291,7 +298,8 @@ static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize,
|
|||||||
BOOL disc = FALSE; /* Discontinuity between @dst and @src */
|
BOOL disc = FALSE; /* Discontinuity between @dst and @src */
|
||||||
int marker; /* End of the inserted runs */
|
int marker; /* End of the inserted runs */
|
||||||
|
|
||||||
if (!dst || !src) {
|
if ( !dst || !src )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Eeek. ntfs_rl_insert() invoked with NULL "
|
ntfs_log_debug( "Eeek. ntfs_rl_insert() invoked with NULL "
|
||||||
"pointer!\n" );
|
"pointer!\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@ -303,7 +311,8 @@ static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize,
|
|||||||
*/
|
*/
|
||||||
if ( loc == 0 )
|
if ( loc == 0 )
|
||||||
disc = ( src[0].vcn > 0 );
|
disc = ( src[0].vcn > 0 );
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
s64 merged_length;
|
s64 merged_length;
|
||||||
|
|
||||||
left = ntfs_rl_are_mergeable( dst + loc - 1, src );
|
left = ntfs_rl_are_mergeable( dst + loc - 1, src );
|
||||||
@ -348,11 +357,15 @@ static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize,
|
|||||||
dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn;
|
dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn;
|
||||||
|
|
||||||
/* Writing beyond the end of the file and there's a discontinuity. */
|
/* Writing beyond the end of the file and there's a discontinuity. */
|
||||||
if (disc) {
|
if ( disc )
|
||||||
if (loc > 0) {
|
{
|
||||||
|
if ( loc > 0 )
|
||||||
|
{
|
||||||
dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length;
|
dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length;
|
||||||
dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
|
dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
dst[loc].vcn = 0;
|
dst[loc].vcn = 0;
|
||||||
dst[loc].length = dst[loc + 1].vcn;
|
dst[loc].length = dst[loc + 1].vcn;
|
||||||
}
|
}
|
||||||
@ -390,7 +403,8 @@ static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize,
|
|||||||
int tail; /* Start of tail of @dst */
|
int tail; /* Start of tail of @dst */
|
||||||
int marker; /* End of the inserted runs */
|
int marker; /* End of the inserted runs */
|
||||||
|
|
||||||
if (!dst || !src) {
|
if ( !dst || !src )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Eeek. ntfs_rl_replace() invoked with NULL "
|
ntfs_log_debug( "Eeek. ntfs_rl_replace() invoked with NULL "
|
||||||
"pointer!\n" );
|
"pointer!\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@ -407,7 +421,8 @@ static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize,
|
|||||||
* ends get merged. The -1 accounts for the run being replaced.
|
* ends get merged. The -1 accounts for the run being replaced.
|
||||||
*/
|
*/
|
||||||
delta = ssize - 1 - left - right;
|
delta = ssize - 1 - left - right;
|
||||||
if (delta > 0) {
|
if ( delta > 0 )
|
||||||
|
{
|
||||||
dst = ntfs_rl_realloc( dst, dsize, dsize + delta );
|
dst = ntfs_rl_realloc( dst, dsize, dsize + delta );
|
||||||
if ( !dst )
|
if ( !dst )
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -471,7 +486,8 @@ static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize,
|
|||||||
static runlist_element *ntfs_rl_split( runlist_element *dst, int dsize,
|
static runlist_element *ntfs_rl_split( runlist_element *dst, int dsize,
|
||||||
runlist_element *src, int ssize, int loc )
|
runlist_element *src, int ssize, int loc )
|
||||||
{
|
{
|
||||||
if (!dst || !src) {
|
if ( !dst || !src )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Eeek. ntfs_rl_split() invoked with NULL pointer!\n" );
|
ntfs_log_debug( "Eeek. ntfs_rl_split() invoked with NULL pointer!\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -524,10 +540,12 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
|||||||
return drl;
|
return drl;
|
||||||
|
|
||||||
/* Check for the case where the first mapping is being done now. */
|
/* Check for the case where the first mapping is being done now. */
|
||||||
if (!drl) {
|
if ( !drl )
|
||||||
|
{
|
||||||
drl = srl;
|
drl = srl;
|
||||||
/* Complete the source runlist if necessary. */
|
/* Complete the source runlist if necessary. */
|
||||||
if (drl[0].vcn) {
|
if ( drl[0].vcn )
|
||||||
|
{
|
||||||
/* Scan to the end of the source runlist. */
|
/* Scan to the end of the source runlist. */
|
||||||
for ( dend = 0; drl[dend].length; dend++ )
|
for ( dend = 0; drl[dend].length; dend++ )
|
||||||
;
|
;
|
||||||
@ -551,7 +569,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
|||||||
si++;
|
si++;
|
||||||
|
|
||||||
/* Can't have an entirely unmapped source runlist. */
|
/* Can't have an entirely unmapped source runlist. */
|
||||||
if (!srl[si].length) {
|
if ( !srl[si].length )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: unmapped source runlist", __FUNCTION__ );
|
ntfs_log_perror( "%s: unmapped source runlist", __FUNCTION__ );
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -565,7 +584,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
|||||||
* be inserted. If we reach the end of @drl, @srl just needs to be
|
* be inserted. If we reach the end of @drl, @srl just needs to be
|
||||||
* appended to @drl.
|
* appended to @drl.
|
||||||
*/
|
*/
|
||||||
for (; drl[di].length; di++) {
|
for ( ; drl[di].length; di++ )
|
||||||
|
{
|
||||||
if ( drl[di].vcn + drl[di].length > srl[sstart].vcn )
|
if ( drl[di].vcn + drl[di].length > srl[sstart].vcn )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -573,7 +593,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
|||||||
|
|
||||||
/* Sanity check for illegal overlaps. */
|
/* Sanity check for illegal overlaps. */
|
||||||
if ( ( drl[di].vcn == srl[si].vcn ) && ( drl[di].lcn >= 0 ) &&
|
if ( ( drl[di].vcn == srl[si].vcn ) && ( drl[di].lcn >= 0 ) &&
|
||||||
(srl[si].lcn >= 0)) {
|
( srl[si].lcn >= 0 ) )
|
||||||
|
{
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
ntfs_log_perror( "Run lists overlap. Cannot merge" );
|
ntfs_log_perror( "Run lists overlap. Cannot merge" );
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -617,31 +638,38 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
|||||||
ntfs_log_debug( "start = %i, finish = %i\n", start, finish );
|
ntfs_log_debug( "start = %i, finish = %i\n", start, finish );
|
||||||
ntfs_log_debug( "ds = %i, ss = %i, dins = %i\n", ds, ss, dins );
|
ntfs_log_debug( "ds = %i, ss = %i, dins = %i\n", ds, ss, dins );
|
||||||
|
|
||||||
if (start) {
|
if ( start )
|
||||||
|
{
|
||||||
if ( finish )
|
if ( finish )
|
||||||
drl = ntfs_rl_replace( drl, ds, srl + sstart, ss, dins );
|
drl = ntfs_rl_replace( drl, ds, srl + sstart, ss, dins );
|
||||||
else
|
else
|
||||||
drl = ntfs_rl_insert( drl, ds, srl + sstart, ss, dins );
|
drl = ntfs_rl_insert( drl, ds, srl + sstart, ss, dins );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( finish )
|
if ( finish )
|
||||||
drl = ntfs_rl_append( drl, ds, srl + sstart, ss, dins );
|
drl = ntfs_rl_append( drl, ds, srl + sstart, ss, dins );
|
||||||
else
|
else
|
||||||
drl = ntfs_rl_split( drl, ds, srl + sstart, ss, dins );
|
drl = ntfs_rl_split( drl, ds, srl + sstart, ss, dins );
|
||||||
}
|
}
|
||||||
if (!drl) {
|
if ( !drl )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Merge failed" );
|
ntfs_log_perror( "Merge failed" );
|
||||||
return drl;
|
return drl;
|
||||||
}
|
}
|
||||||
free( srl );
|
free( srl );
|
||||||
if (marker) {
|
if ( marker )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Triggering marker code.\n" );
|
ntfs_log_debug( "Triggering marker code.\n" );
|
||||||
for ( ds = dend; drl[ds].length; ds++ )
|
for ( ds = dend; drl[ds].length; ds++ )
|
||||||
;
|
;
|
||||||
/* We only need to care if @srl ended after @drl. */
|
/* We only need to care if @srl ended after @drl. */
|
||||||
if (drl[ds].vcn <= marker_vcn) {
|
if ( drl[ds].vcn <= marker_vcn )
|
||||||
|
{
|
||||||
int slots = 0;
|
int slots = 0;
|
||||||
|
|
||||||
if (drl[ds].vcn == marker_vcn) {
|
if ( drl[ds].vcn == marker_vcn )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Old marker = %lli, replacing with "
|
ntfs_log_debug( "Old marker = %lli, replacing with "
|
||||||
"LCN_ENOENT.\n",
|
"LCN_ENOENT.\n",
|
||||||
( long long )drl[ds].lcn );
|
( long long )drl[ds].lcn );
|
||||||
@ -653,13 +681,16 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
|||||||
* @drl or extend an existing one before adding the
|
* @drl or extend an existing one before adding the
|
||||||
* ENOENT terminator.
|
* ENOENT terminator.
|
||||||
*/
|
*/
|
||||||
if (drl[ds].lcn == (LCN)LCN_ENOENT) {
|
if ( drl[ds].lcn == ( LCN )LCN_ENOENT )
|
||||||
|
{
|
||||||
ds--;
|
ds--;
|
||||||
slots = 1;
|
slots = 1;
|
||||||
}
|
}
|
||||||
if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) {
|
if ( drl[ds].lcn != ( LCN )LCN_RL_NOT_MAPPED )
|
||||||
|
{
|
||||||
/* Add an unmapped runlist element. */
|
/* Add an unmapped runlist element. */
|
||||||
if (!slots) {
|
if ( !slots )
|
||||||
|
{
|
||||||
/* FIXME/TODO: We need to have the
|
/* FIXME/TODO: We need to have the
|
||||||
* extra memory already! (AIA)
|
* extra memory already! (AIA)
|
||||||
*/
|
*/
|
||||||
@ -680,7 +711,8 @@ static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
|||||||
drl[ds].length = marker_vcn - drl[ds].vcn;
|
drl[ds].length = marker_vcn - drl[ds].vcn;
|
||||||
/* Finally add the ENOENT terminator. */
|
/* Finally add the ENOENT terminator. */
|
||||||
ds++;
|
ds++;
|
||||||
if (!slots) {
|
if ( !slots )
|
||||||
|
{
|
||||||
/* FIXME/TODO: We need to have the extra
|
/* FIXME/TODO: We need to have the extra
|
||||||
* memory already! (AIA)
|
* memory already! (AIA)
|
||||||
*/
|
*/
|
||||||
@ -797,7 +829,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
( unsigned )le32_to_cpu( attr->type ) );
|
( unsigned )le32_to_cpu( attr->type ) );
|
||||||
/* Make sure attr exists and is non-resident. */
|
/* Make sure attr exists and is non-resident. */
|
||||||
if ( !attr || !attr->non_resident ||
|
if ( !attr || !attr->non_resident ||
|
||||||
sle64_to_cpu(attr->lowest_vcn) < (VCN)0) {
|
sle64_to_cpu( attr->lowest_vcn ) < ( VCN )0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -807,7 +840,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
/* Get start of the mapping pairs array. */
|
/* Get start of the mapping pairs array. */
|
||||||
buf = ( const u8* )attr + le16_to_cpu( attr->mapping_pairs_offset );
|
buf = ( const u8* )attr + le16_to_cpu( attr->mapping_pairs_offset );
|
||||||
attr_end = ( const u8* )attr + le32_to_cpu( attr->length );
|
attr_end = ( const u8* )attr + le32_to_cpu( attr->length );
|
||||||
if (buf < (const u8*)attr || buf > attr_end) {
|
if ( buf < ( const u8* )attr || buf > attr_end )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Corrupt attribute.\n" );
|
ntfs_log_debug( "Corrupt attribute.\n" );
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -820,23 +854,27 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
if ( !rl )
|
if ( !rl )
|
||||||
return NULL;
|
return NULL;
|
||||||
/* Insert unmapped starting element if necessary. */
|
/* Insert unmapped starting element if necessary. */
|
||||||
if (vcn) {
|
if ( vcn )
|
||||||
|
{
|
||||||
rl->vcn = ( VCN )0;
|
rl->vcn = ( VCN )0;
|
||||||
rl->lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
rl->lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
||||||
rl->length = vcn;
|
rl->length = vcn;
|
||||||
rlpos++;
|
rlpos++;
|
||||||
}
|
}
|
||||||
while (buf < attr_end && *buf) {
|
while ( buf < attr_end && *buf )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Allocate more memory if needed, including space for the
|
* Allocate more memory if needed, including space for the
|
||||||
* not-mapped and terminator elements.
|
* not-mapped and terminator elements.
|
||||||
*/
|
*/
|
||||||
if ((int)((rlpos + 3) * sizeof(*old_rl)) > rlsize) {
|
if ( ( int )( ( rlpos + 3 ) * sizeof( *old_rl ) ) > rlsize )
|
||||||
|
{
|
||||||
runlist_element *rl2;
|
runlist_element *rl2;
|
||||||
|
|
||||||
rlsize += 0x1000;
|
rlsize += 0x1000;
|
||||||
rl2 = realloc( rl, rlsize );
|
rl2 = realloc( rl, rlsize );
|
||||||
if (!rl2) {
|
if ( !rl2 )
|
||||||
|
{
|
||||||
int eo = errno;
|
int eo = errno;
|
||||||
free( rl );
|
free( rl );
|
||||||
errno = eo;
|
errno = eo;
|
||||||
@ -854,12 +892,15 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
* length as a signed value so that's how it is...
|
* length as a signed value so that's how it is...
|
||||||
*/
|
*/
|
||||||
b = *buf & 0xf;
|
b = *buf & 0xf;
|
||||||
if (b) {
|
if ( b )
|
||||||
|
{
|
||||||
if ( buf + b > attr_end )
|
if ( buf + b > attr_end )
|
||||||
goto io_error;
|
goto io_error;
|
||||||
for ( deltaxcn = ( s8 )buf[b--]; b; b-- )
|
for ( deltaxcn = ( s8 )buf[b--]; b; b-- )
|
||||||
deltaxcn = ( deltaxcn << 8 ) + buf[b];
|
deltaxcn = ( deltaxcn << 8 ) + buf[b];
|
||||||
} else { /* The length entry is compulsory. */
|
}
|
||||||
|
else /* The length entry is compulsory. */
|
||||||
|
{
|
||||||
ntfs_log_debug( "Missing length entry in mapping pairs "
|
ntfs_log_debug( "Missing length entry in mapping pairs "
|
||||||
"array.\n" );
|
"array.\n" );
|
||||||
deltaxcn = ( s64 ) - 1;
|
deltaxcn = ( s64 ) - 1;
|
||||||
@ -868,7 +909,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
* Assume a negative length to indicate data corruption and
|
* Assume a negative length to indicate data corruption and
|
||||||
* hence clean-up and return NULL.
|
* hence clean-up and return NULL.
|
||||||
*/
|
*/
|
||||||
if (deltaxcn < 0) {
|
if ( deltaxcn < 0 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Invalid length in mapping pairs array.\n" );
|
ntfs_log_debug( "Invalid length in mapping pairs array.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -886,7 +928,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
*/
|
*/
|
||||||
if ( !( *buf & 0xf0 ) )
|
if ( !( *buf & 0xf0 ) )
|
||||||
rl[rlpos].lcn = ( LCN )LCN_HOLE;
|
rl[rlpos].lcn = ( LCN )LCN_HOLE;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* Get the lcn change which really can be negative. */
|
/* Get the lcn change which really can be negative. */
|
||||||
u8 b2 = *buf & 0xf;
|
u8 b2 = *buf & 0xf;
|
||||||
b = b2 + ( ( *buf >> 4 ) & 0xf );
|
b = b2 + ( ( *buf >> 4 ) & 0xf );
|
||||||
@ -904,7 +947,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
* -1. So if either is found give us a message so we
|
* -1. So if either is found give us a message so we
|
||||||
* can investigate it further!
|
* can investigate it further!
|
||||||
*/
|
*/
|
||||||
if (vol->major_ver < 3) {
|
if ( vol->major_ver < 3 )
|
||||||
|
{
|
||||||
if ( deltaxcn == ( LCN ) - 1 )
|
if ( deltaxcn == ( LCN ) - 1 )
|
||||||
ntfs_log_debug( "lcn delta == -1\n" );
|
ntfs_log_debug( "lcn delta == -1\n" );
|
||||||
if ( lcn == ( LCN ) - 1 )
|
if ( lcn == ( LCN ) - 1 )
|
||||||
@ -912,7 +956,8 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Check lcn is not below -1. */
|
/* Check lcn is not below -1. */
|
||||||
if (lcn < (LCN)-1) {
|
if ( lcn < ( LCN ) - 1 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Invalid LCN < -1 in mapping pairs "
|
ntfs_log_debug( "Invalid LCN < -1 in mapping pairs "
|
||||||
"array.\n" );
|
"array.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -932,14 +977,16 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
|
|||||||
* vcn in the runlist - 1, or something has gone badly wrong.
|
* vcn in the runlist - 1, or something has gone badly wrong.
|
||||||
*/
|
*/
|
||||||
deltaxcn = sle64_to_cpu( attr->highest_vcn );
|
deltaxcn = sle64_to_cpu( attr->highest_vcn );
|
||||||
if (deltaxcn && vcn - 1 != deltaxcn) {
|
if ( deltaxcn && vcn - 1 != deltaxcn )
|
||||||
|
{
|
||||||
mpa_err:
|
mpa_err:
|
||||||
ntfs_log_debug( "Corrupt mapping pairs array in non-resident "
|
ntfs_log_debug( "Corrupt mapping pairs array in non-resident "
|
||||||
"attribute.\n" );
|
"attribute.\n" );
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* Setup not mapped runlist element if this is the base extent. */
|
/* Setup not mapped runlist element if this is the base extent. */
|
||||||
if (!attr->lowest_vcn) {
|
if ( !attr->lowest_vcn )
|
||||||
|
{
|
||||||
VCN max_cluster;
|
VCN max_cluster;
|
||||||
|
|
||||||
max_cluster = ( ( sle64_to_cpu( attr->allocated_size ) +
|
max_cluster = ( ( sle64_to_cpu( attr->allocated_size ) +
|
||||||
@ -949,14 +996,16 @@ mpa_err:
|
|||||||
* A highest_vcn of zero means this is a single extent
|
* A highest_vcn of zero means this is a single extent
|
||||||
* attribute so simply terminate the runlist with LCN_ENOENT).
|
* attribute so simply terminate the runlist with LCN_ENOENT).
|
||||||
*/
|
*/
|
||||||
if (deltaxcn) {
|
if ( deltaxcn )
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If there is a difference between the highest_vcn and
|
* If there is a difference between the highest_vcn and
|
||||||
* the highest cluster, the runlist is either corrupt
|
* the highest cluster, the runlist is either corrupt
|
||||||
* or, more likely, there are more extents following
|
* or, more likely, there are more extents following
|
||||||
* this one.
|
* this one.
|
||||||
*/
|
*/
|
||||||
if (deltaxcn < max_cluster) {
|
if ( deltaxcn < max_cluster )
|
||||||
|
{
|
||||||
ntfs_log_debug( "More extents to follow; deltaxcn = "
|
ntfs_log_debug( "More extents to follow; deltaxcn = "
|
||||||
"0x%llx, max_cluster = 0x%llx\n",
|
"0x%llx, max_cluster = 0x%llx\n",
|
||||||
( long long )deltaxcn,
|
( long long )deltaxcn,
|
||||||
@ -965,7 +1014,9 @@ mpa_err:
|
|||||||
vcn += rl[rlpos].length = max_cluster - deltaxcn;
|
vcn += rl[rlpos].length = max_cluster - deltaxcn;
|
||||||
rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
||||||
rlpos++;
|
rlpos++;
|
||||||
} else if (deltaxcn > max_cluster) {
|
}
|
||||||
|
else if ( deltaxcn > max_cluster )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Corrupt attribute. deltaxcn = "
|
ntfs_log_debug( "Corrupt attribute. deltaxcn = "
|
||||||
"0x%llx, max_cluster = 0x%llx\n",
|
"0x%llx, max_cluster = 0x%llx\n",
|
||||||
( long long )deltaxcn,
|
( long long )deltaxcn,
|
||||||
@ -974,14 +1025,16 @@ mpa_err:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl[rlpos].lcn = ( LCN )LCN_ENOENT;
|
rl[rlpos].lcn = ( LCN )LCN_ENOENT;
|
||||||
} else /* Not the base extent. There may be more extents to follow. */
|
}
|
||||||
|
else /* Not the base extent. There may be more extents to follow. */
|
||||||
rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
rl[rlpos].lcn = ( LCN )LCN_RL_NOT_MAPPED;
|
||||||
|
|
||||||
/* Setup terminating runlist element. */
|
/* Setup terminating runlist element. */
|
||||||
rl[rlpos].vcn = vcn;
|
rl[rlpos].vcn = vcn;
|
||||||
rl[rlpos].length = ( s64 )0;
|
rl[rlpos].length = ( s64 )0;
|
||||||
/* If no existing runlist was specified, we are done. */
|
/* If no existing runlist was specified, we are done. */
|
||||||
if (!old_rl) {
|
if ( !old_rl )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Mapping pairs array successfully decompressed:\n" );
|
ntfs_log_debug( "Mapping pairs array successfully decompressed:\n" );
|
||||||
ntfs_debug_runlist_dump( rl );
|
ntfs_debug_runlist_dump( rl );
|
||||||
return rl;
|
return rl;
|
||||||
@ -1051,8 +1104,10 @@ LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
|
|||||||
if ( vcn < rl[0].vcn )
|
if ( vcn < rl[0].vcn )
|
||||||
return ( LCN )LCN_ENOENT;
|
return ( LCN )LCN_ENOENT;
|
||||||
|
|
||||||
for (i = 0; rl[i].length; i++) {
|
for ( i = 0; rl[i].length; i++ )
|
||||||
if (vcn < rl[i+1].vcn) {
|
{
|
||||||
|
if ( vcn < rl[i+1].vcn )
|
||||||
|
{
|
||||||
if ( rl[i].lcn >= ( LCN )0 )
|
if ( rl[i].lcn >= ( LCN )0 )
|
||||||
return rl[i].lcn + ( vcn - rl[i].vcn );
|
return rl[i].lcn + ( vcn - rl[i].vcn );
|
||||||
return rl[i].lcn;
|
return rl[i].lcn;
|
||||||
@ -1098,7 +1153,8 @@ s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
|
|||||||
s64 bytes_read, to_read, ofs, total;
|
s64 bytes_read, to_read, ofs, total;
|
||||||
int err = EIO;
|
int err = EIO;
|
||||||
|
|
||||||
if (!vol || !rl || pos < 0 || count < 0) {
|
if ( !vol || !rl || pos < 0 || count < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "Failed to read runlist [vol: %p rl: %p "
|
ntfs_log_perror( "Failed to read runlist [vol: %p rl: %p "
|
||||||
"pos: %lld count: %lld]", vol, rl,
|
"pos: %lld count: %lld]", vol, rl,
|
||||||
@ -1113,10 +1169,12 @@ s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
|
|||||||
ofs += ( rl->length << vol->cluster_size_bits );
|
ofs += ( rl->length << vol->cluster_size_bits );
|
||||||
/* Offset in the run at which to begin reading. */
|
/* Offset in the run at which to begin reading. */
|
||||||
ofs = pos - ofs;
|
ofs = pos - ofs;
|
||||||
for (total = 0LL; count; rl++, ofs = 0) {
|
for ( total = 0LL; count; rl++, ofs = 0 )
|
||||||
|
{
|
||||||
if ( !rl->length )
|
if ( !rl->length )
|
||||||
goto rl_err_out;
|
goto rl_err_out;
|
||||||
if (rl->lcn < (LCN)0) {
|
if ( rl->lcn < ( LCN )0 )
|
||||||
|
{
|
||||||
if ( rl->lcn != ( LCN )LCN_HOLE )
|
if ( rl->lcn != ( LCN )LCN_HOLE )
|
||||||
goto rl_err_out;
|
goto rl_err_out;
|
||||||
/* It is a hole. Just fill buffer @b with zeroes. */
|
/* It is a hole. Just fill buffer @b with zeroes. */
|
||||||
@ -1136,7 +1194,8 @@ retry:
|
|||||||
bytes_read = ntfs_pread( vol->dev, ( rl->lcn <<
|
bytes_read = ntfs_pread( vol->dev, ( rl->lcn <<
|
||||||
vol->cluster_size_bits ) + ofs, to_read, b );
|
vol->cluster_size_bits ) + ofs, to_read, b );
|
||||||
/* If everything ok, update progress counters and continue. */
|
/* If everything ok, update progress counters and continue. */
|
||||||
if (bytes_read > 0) {
|
if ( bytes_read > 0 )
|
||||||
|
{
|
||||||
total += bytes_read;
|
total += bytes_read;
|
||||||
count -= bytes_read;
|
count -= bytes_read;
|
||||||
b = ( u8* )b + bytes_read;
|
b = ( u8* )b + bytes_read;
|
||||||
@ -1187,7 +1246,8 @@ s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
|
|||||||
s64 written, to_write, total = 0;
|
s64 written, to_write, total = 0;
|
||||||
int err = EIO;
|
int err = EIO;
|
||||||
|
|
||||||
if (!vol || !rl || pos < 0 || count < 0) {
|
if ( !vol || !rl || pos < 0 || count < 0 )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "Failed to write runlist [vol: %p rl: %p "
|
ntfs_log_perror( "Failed to write runlist [vol: %p rl: %p "
|
||||||
"pos: %lld count: %lld]", vol, rl,
|
"pos: %lld count: %lld]", vol, rl,
|
||||||
@ -1198,16 +1258,19 @@ s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
|
|||||||
goto out;
|
goto out;
|
||||||
/* Seek in @rl to the run containing @pos. */
|
/* Seek in @rl to the run containing @pos. */
|
||||||
while ( rl->length && ( ofs + ( rl->length <<
|
while ( rl->length && ( ofs + ( rl->length <<
|
||||||
vol->cluster_size_bits) <= pos)) {
|
vol->cluster_size_bits ) <= pos ) )
|
||||||
|
{
|
||||||
ofs += ( rl->length << vol->cluster_size_bits );
|
ofs += ( rl->length << vol->cluster_size_bits );
|
||||||
rl++;
|
rl++;
|
||||||
}
|
}
|
||||||
/* Offset in the run at which to begin writing. */
|
/* Offset in the run at which to begin writing. */
|
||||||
ofs = pos - ofs;
|
ofs = pos - ofs;
|
||||||
for (total = 0LL; count; rl++, ofs = 0) {
|
for ( total = 0LL; count; rl++, ofs = 0 )
|
||||||
|
{
|
||||||
if ( !rl->length )
|
if ( !rl->length )
|
||||||
goto rl_err_out;
|
goto rl_err_out;
|
||||||
if (rl->lcn < (LCN)0) {
|
if ( rl->lcn < ( LCN )0 )
|
||||||
|
{
|
||||||
|
|
||||||
if ( rl->lcn != ( LCN )LCN_HOLE )
|
if ( rl->lcn != ( LCN )LCN_HOLE )
|
||||||
goto rl_err_out;
|
goto rl_err_out;
|
||||||
@ -1231,7 +1294,8 @@ retry:
|
|||||||
else
|
else
|
||||||
written = to_write;
|
written = to_write;
|
||||||
/* If everything ok, update progress counters and continue. */
|
/* If everything ok, update progress counters and continue. */
|
||||||
if (written > 0) {
|
if ( written > 0 )
|
||||||
|
{
|
||||||
total += written;
|
total += written;
|
||||||
count -= written;
|
count -= written;
|
||||||
b = ( u8* )b + written;
|
b = ( u8* )b + written;
|
||||||
@ -1275,12 +1339,15 @@ int ntfs_get_nr_significant_bytes(const s64 n)
|
|||||||
|
|
||||||
l = ( n < 0 ? ~n : n );
|
l = ( n < 0 ? ~n : n );
|
||||||
i = 1;
|
i = 1;
|
||||||
if (l >= 128) {
|
if ( l >= 128 )
|
||||||
|
{
|
||||||
l >>= 7;
|
l >>= 7;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
i++;
|
i++;
|
||||||
l >>= 8;
|
l >>= 8;
|
||||||
} while (l);
|
}
|
||||||
|
while ( l );
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -1311,14 +1378,17 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
|||||||
LCN prev_lcn;
|
LCN prev_lcn;
|
||||||
int rls;
|
int rls;
|
||||||
|
|
||||||
if (start_vcn < 0) {
|
if ( start_vcn < 0 )
|
||||||
|
{
|
||||||
ntfs_log_trace( "start_vcn %lld (should be >= 0)\n",
|
ntfs_log_trace( "start_vcn %lld (should be >= 0)\n",
|
||||||
( long long ) start_vcn );
|
( long long ) start_vcn );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto errno_set;
|
goto errno_set;
|
||||||
}
|
}
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
if (start_vcn) {
|
{
|
||||||
|
if ( start_vcn )
|
||||||
|
{
|
||||||
ntfs_log_trace( "rl NULL, start_vcn %lld (should be > 0)\n",
|
ntfs_log_trace( "rl NULL, start_vcn %lld (should be > 0)\n",
|
||||||
( long long ) start_vcn );
|
( long long ) start_vcn );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@ -1330,7 +1400,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
|||||||
/* Skip to runlist element containing @start_vcn. */
|
/* Skip to runlist element containing @start_vcn. */
|
||||||
while ( rl->length && start_vcn >= rl[1].vcn )
|
while ( rl->length && start_vcn >= rl[1].vcn )
|
||||||
rl++;
|
rl++;
|
||||||
if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) {
|
if ( ( !rl->length && start_vcn > rl->vcn ) || start_vcn < rl->vcn )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto errno_set;
|
goto errno_set;
|
||||||
}
|
}
|
||||||
@ -1338,7 +1409,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
|||||||
/* Always need the terminating zero byte. */
|
/* Always need the terminating zero byte. */
|
||||||
rls = 1;
|
rls = 1;
|
||||||
/* Do the first partial run if present. */
|
/* Do the first partial run if present. */
|
||||||
if (start_vcn > rl->vcn) {
|
if ( start_vcn > rl->vcn )
|
||||||
|
{
|
||||||
s64 delta;
|
s64 delta;
|
||||||
|
|
||||||
/* We know rl->length != 0 already. */
|
/* We know rl->length != 0 already. */
|
||||||
@ -1354,7 +1426,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
|||||||
* Note: this assumes that on NTFS 1.2-, holes are stored with
|
* Note: this assumes that on NTFS 1.2-, holes are stored with
|
||||||
* an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
|
* an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
|
||||||
*/
|
*/
|
||||||
if (rl->lcn >= 0 || vol->major_ver < 3) {
|
if ( rl->lcn >= 0 || vol->major_ver < 3 )
|
||||||
|
{
|
||||||
prev_lcn = rl->lcn;
|
prev_lcn = rl->lcn;
|
||||||
if ( rl->lcn >= 0 )
|
if ( rl->lcn >= 0 )
|
||||||
prev_lcn += delta;
|
prev_lcn += delta;
|
||||||
@ -1365,7 +1438,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
|||||||
rl++;
|
rl++;
|
||||||
}
|
}
|
||||||
/* Do the full runs. */
|
/* Do the full runs. */
|
||||||
for (; rl->length && (rls <= max_size); rl++) {
|
for ( ; rl->length && ( rls <= max_size ); rl++ )
|
||||||
|
{
|
||||||
if ( rl->length < 0 || rl->lcn < LCN_HOLE )
|
if ( rl->length < 0 || rl->lcn < LCN_HOLE )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
/* Header byte + length. */
|
/* Header byte + length. */
|
||||||
@ -1377,7 +1451,8 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
|||||||
* Note: this assumes that on NTFS 1.2-, holes are stored with
|
* Note: this assumes that on NTFS 1.2-, holes are stored with
|
||||||
* an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
|
* an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
|
||||||
*/
|
*/
|
||||||
if (rl->lcn >= 0 || vol->major_ver < 3) {
|
if ( rl->lcn >= 0 || vol->major_ver < 3 )
|
||||||
|
{
|
||||||
/* Change in lcn. */
|
/* Change in lcn. */
|
||||||
rls += ntfs_get_nr_significant_bytes( rl->lcn -
|
rls += ntfs_get_nr_significant_bytes( rl->lcn -
|
||||||
prev_lcn );
|
prev_lcn );
|
||||||
@ -1421,21 +1496,26 @@ int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n)
|
|||||||
s8 j;
|
s8 j;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
if ( dst > dst_max )
|
if ( dst > dst_max )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
*dst++ = l & 0xffLL;
|
*dst++ = l & 0xffLL;
|
||||||
l >>= 8;
|
l >>= 8;
|
||||||
i++;
|
i++;
|
||||||
} while (l != 0LL && l != -1LL);
|
}
|
||||||
|
while ( l != 0LL && l != -1LL );
|
||||||
j = ( n >> 8 * ( i - 1 ) ) & 0xff;
|
j = ( n >> 8 * ( i - 1 ) ) & 0xff;
|
||||||
/* If the sign bit is wrong, we need an extra byte. */
|
/* If the sign bit is wrong, we need an extra byte. */
|
||||||
if (n < 0LL && j >= 0) {
|
if ( n < 0LL && j >= 0 )
|
||||||
|
{
|
||||||
if ( dst > dst_max )
|
if ( dst > dst_max )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
i++;
|
i++;
|
||||||
*dst = ( u8 ) - 1;
|
*dst = ( u8 ) - 1;
|
||||||
} else if (n > 0LL && j < 0) {
|
}
|
||||||
|
else if ( n > 0LL && j < 0 )
|
||||||
|
{
|
||||||
if ( dst > dst_max )
|
if ( dst > dst_max )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
i++;
|
i++;
|
||||||
@ -1489,7 +1569,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
|||||||
|
|
||||||
if ( start_vcn < 0 )
|
if ( start_vcn < 0 )
|
||||||
goto val_err;
|
goto val_err;
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
if ( start_vcn )
|
if ( start_vcn )
|
||||||
goto val_err;
|
goto val_err;
|
||||||
if ( stop_rl )
|
if ( stop_rl )
|
||||||
@ -1510,7 +1591,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
|||||||
dst_max = dst + dst_len - 1;
|
dst_max = dst + dst_len - 1;
|
||||||
prev_lcn = 0;
|
prev_lcn = 0;
|
||||||
/* Do the first partial run if present. */
|
/* Do the first partial run if present. */
|
||||||
if (start_vcn > rl->vcn) {
|
if ( start_vcn > rl->vcn )
|
||||||
|
{
|
||||||
s64 delta;
|
s64 delta;
|
||||||
|
|
||||||
/* We know rl->length != 0 already. */
|
/* We know rl->length != 0 already. */
|
||||||
@ -1531,7 +1613,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
|||||||
* case on NT4. - We assume that we just need to write the lcn
|
* case on NT4. - We assume that we just need to write the lcn
|
||||||
* change until someone tells us otherwise... (AIA)
|
* change until someone tells us otherwise... (AIA)
|
||||||
*/
|
*/
|
||||||
if (rl->lcn >= 0 || vol->major_ver < 3) {
|
if ( rl->lcn >= 0 || vol->major_ver < 3 )
|
||||||
|
{
|
||||||
prev_lcn = rl->lcn;
|
prev_lcn = rl->lcn;
|
||||||
if ( rl->lcn >= 0 )
|
if ( rl->lcn >= 0 )
|
||||||
prev_lcn += delta;
|
prev_lcn += delta;
|
||||||
@ -1540,7 +1623,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
|||||||
len_len, dst_max, prev_lcn );
|
len_len, dst_max, prev_lcn );
|
||||||
if ( lcn_len < 0 )
|
if ( lcn_len < 0 )
|
||||||
goto size_err;
|
goto size_err;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
lcn_len = 0;
|
lcn_len = 0;
|
||||||
dst_next = dst + len_len + lcn_len + 1;
|
dst_next = dst + len_len + lcn_len + 1;
|
||||||
if ( dst_next > dst_max )
|
if ( dst_next > dst_max )
|
||||||
@ -1553,7 +1637,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
|||||||
rl++;
|
rl++;
|
||||||
}
|
}
|
||||||
/* Do the full runs. */
|
/* Do the full runs. */
|
||||||
for (; rl->length; rl++) {
|
for ( ; rl->length; rl++ )
|
||||||
|
{
|
||||||
if ( rl->length < 0 || rl->lcn < LCN_HOLE )
|
if ( rl->length < 0 || rl->lcn < LCN_HOLE )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
/* Write length. */
|
/* Write length. */
|
||||||
@ -1570,14 +1655,16 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
|||||||
* case on NT4. - We assume that we just need to write the lcn
|
* case on NT4. - We assume that we just need to write the lcn
|
||||||
* change until someone tells us otherwise... (AIA)
|
* change until someone tells us otherwise... (AIA)
|
||||||
*/
|
*/
|
||||||
if (rl->lcn >= 0 || vol->major_ver < 3) {
|
if ( rl->lcn >= 0 || vol->major_ver < 3 )
|
||||||
|
{
|
||||||
/* Write change in lcn. */
|
/* Write change in lcn. */
|
||||||
lcn_len = ntfs_write_significant_bytes( dst + 1 +
|
lcn_len = ntfs_write_significant_bytes( dst + 1 +
|
||||||
len_len, dst_max, rl->lcn - prev_lcn );
|
len_len, dst_max, rl->lcn - prev_lcn );
|
||||||
if ( lcn_len < 0 )
|
if ( lcn_len < 0 )
|
||||||
goto size_err;
|
goto size_err;
|
||||||
prev_lcn = rl->lcn;
|
prev_lcn = rl->lcn;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
lcn_len = 0;
|
lcn_len = 0;
|
||||||
dst_next = dst + len_len + lcn_len + 1;
|
dst_next = dst + len_len + lcn_len + 1;
|
||||||
if ( dst_next > dst_max )
|
if ( dst_next > dst_max )
|
||||||
@ -1635,7 +1722,8 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
|
|||||||
runlist *rl;
|
runlist *rl;
|
||||||
BOOL is_end = FALSE;
|
BOOL is_end = FALSE;
|
||||||
|
|
||||||
if (!arl || !*arl) {
|
if ( !arl || !*arl )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
if ( !arl )
|
if ( !arl )
|
||||||
ntfs_log_perror( "rl_truncate error: arl: %p", arl );
|
ntfs_log_perror( "rl_truncate error: arl: %p", arl );
|
||||||
@ -1647,20 +1735,23 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
|
|||||||
|
|
||||||
rl = *arl;
|
rl = *arl;
|
||||||
|
|
||||||
if (start_vcn < rl->vcn) {
|
if ( start_vcn < rl->vcn )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "Start_vcn lies outside front of runlist" );
|
ntfs_log_perror( "Start_vcn lies outside front of runlist" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the starting vcn in the run list. */
|
/* Find the starting vcn in the run list. */
|
||||||
while (rl->length) {
|
while ( rl->length )
|
||||||
|
{
|
||||||
if ( start_vcn < rl[1].vcn )
|
if ( start_vcn < rl[1].vcn )
|
||||||
break;
|
break;
|
||||||
rl++;
|
rl++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rl->length) {
|
if ( !rl->length )
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_trace( "Truncating already truncated runlist?\n" );
|
ntfs_log_trace( "Truncating already truncated runlist?\n" );
|
||||||
return -1;
|
return -1;
|
||||||
@ -1674,7 +1765,8 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
|
|||||||
* element a terminator instead of the truncated runlist
|
* element a terminator instead of the truncated runlist
|
||||||
* element itself.
|
* element itself.
|
||||||
*/
|
*/
|
||||||
if (rl->length) {
|
if ( rl->length )
|
||||||
|
{
|
||||||
++rl;
|
++rl;
|
||||||
if ( !rl->length )
|
if ( !rl->length )
|
||||||
is_end = TRUE;
|
is_end = TRUE;
|
||||||
@ -1708,15 +1800,18 @@ int ntfs_rl_sparse(runlist *rl)
|
|||||||
{
|
{
|
||||||
runlist *rlc;
|
runlist *rlc;
|
||||||
|
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: ", __FUNCTION__ );
|
ntfs_log_perror( "%s: ", __FUNCTION__ );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( rlc = rl; rlc->length; rlc++ )
|
for ( rlc = rl; rlc->length; rlc++ )
|
||||||
if (rlc->lcn < 0) {
|
if ( rlc->lcn < 0 )
|
||||||
if (rlc->lcn != LCN_HOLE) {
|
{
|
||||||
|
if ( rlc->lcn != LCN_HOLE )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
|
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
|
||||||
return -1;
|
return -1;
|
||||||
@ -1738,20 +1833,25 @@ s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl)
|
|||||||
runlist *rlc;
|
runlist *rlc;
|
||||||
s64 ret = 0;
|
s64 ret = 0;
|
||||||
|
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: ", __FUNCTION__ );
|
ntfs_log_perror( "%s: ", __FUNCTION__ );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (rlc = rl; rlc->length; rlc++) {
|
for ( rlc = rl; rlc->length; rlc++ )
|
||||||
if (rlc->lcn < 0) {
|
{
|
||||||
if (rlc->lcn != LCN_HOLE) {
|
if ( rlc->lcn < 0 )
|
||||||
|
{
|
||||||
|
if ( rlc->lcn != LCN_HOLE )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
|
ntfs_log_perror( "%s: bad runlist", __FUNCTION__ );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ret += rlc->length;
|
ret += rlc->length;
|
||||||
}
|
}
|
||||||
return ret << vol->cluster_size_bits;
|
return ret << vol->cluster_size_bits;
|
||||||
@ -1784,7 +1884,8 @@ static void test_rl_dump_runlist(const runlist_element *rl)
|
|||||||
int i;
|
int i;
|
||||||
const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "XXXX" };
|
const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "XXXX" };
|
||||||
|
|
||||||
if (!rl) {
|
if ( !rl )
|
||||||
|
{
|
||||||
printf( " Run list not present.\n" );
|
printf( " Run list not present.\n" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1793,24 +1894,28 @@ static void test_rl_dump_runlist(const runlist_element *rl)
|
|||||||
for ( len = 0; rl[len].length; len++ ) ;
|
for ( len = 0; rl[len].length; len++ ) ;
|
||||||
|
|
||||||
printf( " VCN LCN len\n" );
|
printf( " VCN LCN len\n" );
|
||||||
for (i = 0; ; i++, rl++) {
|
for ( i = 0; ; i++, rl++ )
|
||||||
|
{
|
||||||
LCN lcn = rl->lcn;
|
LCN lcn = rl->lcn;
|
||||||
|
|
||||||
if ((abbr) && (len > 20)) {
|
if ( ( abbr ) && ( len > 20 ) )
|
||||||
|
{
|
||||||
if ( i == 4 )
|
if ( i == 4 )
|
||||||
printf( " ...\n" );
|
printf( " ...\n" );
|
||||||
if ( ( i > 3 ) && ( i < ( len - 3 ) ) )
|
if ( ( i > 3 ) && ( i < ( len - 3 ) ) )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lcn < (LCN)0) {
|
if ( lcn < ( LCN )0 )
|
||||||
|
{
|
||||||
int ind = -lcn - 1;
|
int ind = -lcn - 1;
|
||||||
|
|
||||||
if ( ind > -LCN_ENOENT - 1 )
|
if ( ind > -LCN_ENOENT - 1 )
|
||||||
ind = 3;
|
ind = 3;
|
||||||
printf( "%8lld %8s %8lld\n",
|
printf( "%8lld %8s %8lld\n",
|
||||||
rl->vcn, lcn_str[ind], rl->length );
|
rl->vcn, lcn_str[ind], rl->length );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
printf( "%8lld %8lld %8lld\n",
|
printf( "%8lld %8lld %8lld\n",
|
||||||
rl->vcn, rl->lcn, rl->length );
|
rl->vcn, rl->lcn, rl->length );
|
||||||
if ( !rl->length )
|
if ( !rl->length )
|
||||||
@ -1862,12 +1967,14 @@ static int test_rl_read_buffer(const char *file, u8 *buf, int bufsize)
|
|||||||
FILE *fptr;
|
FILE *fptr;
|
||||||
|
|
||||||
fptr = fopen( file, "r" );
|
fptr = fopen( file, "r" );
|
||||||
if (!fptr) {
|
if ( !fptr )
|
||||||
|
{
|
||||||
printf( "open %s\n", file );
|
printf( "open %s\n", file );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(buf, bufsize, 1, fptr) == 99) {
|
if ( fread( buf, bufsize, 1, fptr ) == 99 )
|
||||||
|
{
|
||||||
printf( "read %s\n", file );
|
printf( "read %s\n", file );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1901,13 +2008,16 @@ static runlist_element * test_rl_pure_src(BOOL contig, BOOL multi, int vcn, int
|
|||||||
if ( !result )
|
if ( !result )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (multi) {
|
if ( multi )
|
||||||
|
{
|
||||||
MKRL( result + 0, vcn + ( 0*len / 4 ), fudge + vcn + 1000 + ( 0*len / 4 ), len / 4 )
|
MKRL( result + 0, vcn + ( 0*len / 4 ), fudge + vcn + 1000 + ( 0*len / 4 ), len / 4 )
|
||||||
MKRL( result + 1, vcn + ( 1*len / 4 ), fudge + vcn + 1000 + ( 1*len / 4 ), len / 4 )
|
MKRL( result + 1, vcn + ( 1*len / 4 ), fudge + vcn + 1000 + ( 1*len / 4 ), len / 4 )
|
||||||
MKRL( result + 2, vcn + ( 2*len / 4 ), fudge + vcn + 1000 + ( 2*len / 4 ), len / 4 )
|
MKRL( result + 2, vcn + ( 2*len / 4 ), fudge + vcn + 1000 + ( 2*len / 4 ), len / 4 )
|
||||||
MKRL( result + 3, vcn + ( 3*len / 4 ), fudge + vcn + 1000 + ( 3*len / 4 ), len / 4 )
|
MKRL( result + 3, vcn + ( 3*len / 4 ), fudge + vcn + 1000 + ( 3*len / 4 ), len / 4 )
|
||||||
MKRL( result + 4, vcn + ( 4*len / 4 ), LCN_RL_NOT_MAPPED, 0 )
|
MKRL( result + 4, vcn + ( 4*len / 4 ), LCN_RL_NOT_MAPPED, 0 )
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MKRL( result + 0, vcn, fudge + vcn + 1000, len )
|
MKRL( result + 0, vcn, fudge + vcn + 1000, len )
|
||||||
MKRL( result + 1, vcn + len, LCN_RL_NOT_MAPPED, 0 )
|
MKRL( result + 1, vcn + len, LCN_RL_NOT_MAPPED, 0 )
|
||||||
}
|
}
|
||||||
@ -1936,7 +2046,8 @@ static void test_rl_pure_test(int test, BOOL contig, BOOL multi, int vcn, int le
|
|||||||
|
|
||||||
src = test_rl_pure_src( contig, multi, vcn, len );
|
src = test_rl_pure_src( contig, multi, vcn, len );
|
||||||
dst = ntfs_malloc( 4096 );
|
dst = ntfs_malloc( 4096 );
|
||||||
if (!src || !dst) {
|
if ( !src || !dst )
|
||||||
|
{
|
||||||
printf( "Test %2d ---------- FAILED! (no free memory?)\n", test );
|
printf( "Test %2d ---------- FAILED! (no free memory?)\n", test );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1961,7 +2072,8 @@ static void test_rl_pure_test(int test, BOOL contig, BOOL multi, int vcn, int le
|
|||||||
static void test_rl_pure( char *contig, char *multi )
|
static void test_rl_pure( char *contig, char *multi )
|
||||||
{
|
{
|
||||||
/* VCN, LCN, len */
|
/* VCN, LCN, len */
|
||||||
static runlist_element file1[] = {
|
static runlist_element file1[] =
|
||||||
|
{
|
||||||
{ 0, -1, 100 }, /* HOLE */
|
{ 0, -1, 100 }, /* HOLE */
|
||||||
{ 100, 1100, 100 }, /* DATA */
|
{ 100, 1100, 100 }, /* DATA */
|
||||||
{ 200, -1, 100 }, /* HOLE */
|
{ 200, -1, 100 }, /* HOLE */
|
||||||
@ -1969,19 +2081,23 @@ static void test_rl_pure(char *contig, char *multi)
|
|||||||
{ 400, -1, 100 }, /* HOLE */
|
{ 400, -1, 100 }, /* HOLE */
|
||||||
{ 500, -3, 0 } /* NOENT */
|
{ 500, -3, 0 } /* NOENT */
|
||||||
};
|
};
|
||||||
static runlist_element file2[] = {
|
static runlist_element file2[] =
|
||||||
|
{
|
||||||
{ 0, 1000, 100 }, /* DATA */
|
{ 0, 1000, 100 }, /* DATA */
|
||||||
{ 100, -1, 100 }, /* HOLE */
|
{ 100, -1, 100 }, /* HOLE */
|
||||||
{ 200, -3, 0 } /* NOENT */
|
{ 200, -3, 0 } /* NOENT */
|
||||||
};
|
};
|
||||||
static runlist_element file3[] = {
|
static runlist_element file3[] =
|
||||||
|
{
|
||||||
{ 0, 1000, 100 }, /* DATA */
|
{ 0, 1000, 100 }, /* DATA */
|
||||||
{ 100, -3, 0 } /* NOENT */
|
{ 100, -3, 0 } /* NOENT */
|
||||||
};
|
};
|
||||||
static runlist_element file4[] = {
|
static runlist_element file4[] =
|
||||||
|
{
|
||||||
{ 0, -3, 0 } /* NOENT */
|
{ 0, -3, 0 } /* NOENT */
|
||||||
};
|
};
|
||||||
static runlist_element file5[] = {
|
static runlist_element file5[] =
|
||||||
|
{
|
||||||
{ 0, -2, 100 }, /* NOTMAP */
|
{ 0, -2, 100 }, /* NOTMAP */
|
||||||
{ 100, 1100, 100 }, /* DATA */
|
{ 100, 1100, 100 }, /* DATA */
|
||||||
{ 200, -2, 100 }, /* NOTMAP */
|
{ 200, -2, 100 }, /* NOTMAP */
|
||||||
@ -1989,7 +2105,8 @@ static void test_rl_pure(char *contig, char *multi)
|
|||||||
{ 400, -2, 100 }, /* NOTMAP */
|
{ 400, -2, 100 }, /* NOTMAP */
|
||||||
{ 500, -3, 0 } /* NOENT */
|
{ 500, -3, 0 } /* NOENT */
|
||||||
};
|
};
|
||||||
static runlist_element file6[] = {
|
static runlist_element file6[] =
|
||||||
|
{
|
||||||
{ 0, 1000, 100 }, /* DATA */
|
{ 0, 1000, 100 }, /* DATA */
|
||||||
{ 100, -2, 100 }, /* NOTMAP */
|
{ 100, -2, 100 }, /* NOTMAP */
|
||||||
{ 200, -3, 0 } /* NOENT */
|
{ 200, -3, 0 } /* NOENT */
|
||||||
@ -2000,7 +2117,8 @@ static void test_rl_pure(char *contig, char *multi)
|
|||||||
c = TRUE;
|
c = TRUE;
|
||||||
else if ( strcmp( contig, "noncontig" ) == 0 )
|
else if ( strcmp( contig, "noncontig" ) == 0 )
|
||||||
c = FALSE;
|
c = FALSE;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
printf( "rl pure [contig|noncontig] [single|multi]\n" );
|
printf( "rl pure [contig|noncontig] [single|multi]\n" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2008,7 +2126,8 @@ static void test_rl_pure(char *contig, char *multi)
|
|||||||
m = TRUE;
|
m = TRUE;
|
||||||
else if ( strcmp( multi, "single" ) == 0 )
|
else if ( strcmp( multi, "single" ) == 0 )
|
||||||
m = FALSE;
|
m = FALSE;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
printf( "rl pure [contig|noncontig] [single|multi]\n" );
|
printf( "rl pure [contig|noncontig] [single|multi]\n" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ typedef runlist_element runlist;
|
|||||||
* When lcn == -1 this means that the count vcns starting at vcn are not
|
* When lcn == -1 this means that the count vcns starting at vcn are not
|
||||||
* physically allocated (i.e. this is a hole / data is sparse).
|
* physically allocated (i.e. this is a hole / data is sparse).
|
||||||
*/
|
*/
|
||||||
struct _runlist_element {/* In memory vcn to lcn mapping structure element. */
|
struct _runlist_element /* In memory vcn to lcn mapping structure element. */
|
||||||
|
{
|
||||||
VCN vcn; /* vcn = Starting virtual cluster number. */
|
VCN vcn; /* vcn = Starting virtual cluster number. */
|
||||||
LCN lcn; /* lcn = Starting logical cluster number. */
|
LCN lcn; /* lcn = Starting logical cluster number. */
|
||||||
s64 length; /* Run length in clusters. */
|
s64 length; /* Run length in clusters. */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -50,7 +50,8 @@ typedef u32 be32;
|
|||||||
* item in the mapping list
|
* item in the mapping list
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct MAPPING {
|
struct MAPPING
|
||||||
|
{
|
||||||
struct MAPPING *next;
|
struct MAPPING *next;
|
||||||
int xid; /* linux id : uid or gid */
|
int xid; /* linux id : uid or gid */
|
||||||
SID *sid; /* Windows id : usid or gsid */
|
SID *sid; /* Windows id : usid or gsid */
|
||||||
@ -63,7 +64,8 @@ struct MAPPING {
|
|||||||
* Note : this cache is not organized as a generic cache
|
* Note : this cache is not organized as a generic cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_PERMISSIONS {
|
struct CACHED_PERMISSIONS
|
||||||
|
{
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
le32 inh_fileid;
|
le32 inh_fileid;
|
||||||
@ -80,7 +82,8 @@ struct CACHED_PERMISSIONS {
|
|||||||
* Entry in the permissions cache for directories with no security_id
|
* Entry in the permissions cache for directories with no security_id
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_PERMISSIONS_LEGACY {
|
struct CACHED_PERMISSIONS_LEGACY
|
||||||
|
{
|
||||||
struct CACHED_PERMISSIONS_LEGACY *next;
|
struct CACHED_PERMISSIONS_LEGACY *next;
|
||||||
struct CACHED_PERMISSIONS_LEGACY *previous;
|
struct CACHED_PERMISSIONS_LEGACY *previous;
|
||||||
void *variable;
|
void *variable;
|
||||||
@ -94,7 +97,8 @@ struct CACHED_PERMISSIONS_LEGACY {
|
|||||||
* Entry in the securid cache
|
* Entry in the securid cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_SECURID {
|
struct CACHED_SECURID
|
||||||
|
{
|
||||||
struct CACHED_SECURID *next;
|
struct CACHED_SECURID *next;
|
||||||
struct CACHED_SECURID *previous;
|
struct CACHED_SECURID *previous;
|
||||||
void *variable;
|
void *variable;
|
||||||
@ -111,7 +115,8 @@ struct CACHED_SECURID {
|
|||||||
* (has no cache structure by itself)
|
* (has no cache structure by itself)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_PERMISSIONS_HEADER {
|
struct CACHED_PERMISSIONS_HEADER
|
||||||
|
{
|
||||||
unsigned int last;
|
unsigned int last;
|
||||||
/* statistics for permissions */
|
/* statistics for permissions */
|
||||||
unsigned long p_writes;
|
unsigned long p_writes;
|
||||||
@ -123,7 +128,8 @@ struct CACHED_PERMISSIONS_HEADER {
|
|||||||
* The whole permissions cache
|
* The whole permissions cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct PERMISSIONS_CACHE {
|
struct PERMISSIONS_CACHE
|
||||||
|
{
|
||||||
struct CACHED_PERMISSIONS_HEADER head;
|
struct CACHED_PERMISSIONS_HEADER head;
|
||||||
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
|
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
|
||||||
} ;
|
} ;
|
||||||
@ -132,7 +138,8 @@ struct PERMISSIONS_CACHE {
|
|||||||
* Security flags values
|
* Security flags values
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
||||||
SECURITY_RAW, /* force same ownership/permissions on files */
|
SECURITY_RAW, /* force same ownership/permissions on files */
|
||||||
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
||||||
@ -146,7 +153,8 @@ enum {
|
|||||||
|
|
||||||
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
|
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
|
||||||
|
|
||||||
struct SECURITY_CONTEXT {
|
struct SECURITY_CONTEXT
|
||||||
|
{
|
||||||
ntfs_volume *vol;
|
ntfs_volume *vol;
|
||||||
struct MAPPING *mapping[MAPCOUNT];
|
struct MAPPING *mapping[MAPCOUNT];
|
||||||
struct PERMISSIONS_CACHE **pseccache;
|
struct PERMISSIONS_CACHE **pseccache;
|
||||||
@ -162,20 +170,23 @@ struct SECURITY_CONTEXT {
|
|||||||
* Posix ACL structures
|
* Posix ACL structures
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct POSIX_ACE {
|
struct POSIX_ACE
|
||||||
|
{
|
||||||
u16 tag;
|
u16 tag;
|
||||||
u16 perms;
|
u16 perms;
|
||||||
s32 id;
|
s32 id;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct POSIX_ACL {
|
struct POSIX_ACL
|
||||||
|
{
|
||||||
u8 version;
|
u8 version;
|
||||||
u8 flags;
|
u8 flags;
|
||||||
u16 filler;
|
u16 filler;
|
||||||
struct POSIX_ACE ace[0];
|
struct POSIX_ACE ace[0];
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct POSIX_SECURITY {
|
struct POSIX_SECURITY
|
||||||
|
{
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
int acccnt;
|
int acccnt;
|
||||||
int defcnt;
|
int defcnt;
|
||||||
@ -188,7 +199,8 @@ struct POSIX_SECURITY {
|
|||||||
* Posix tags, cpu-endian 16 bits
|
* Posix tags, cpu-endian 16 bits
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
POSIX_ACL_USER_OBJ = 1,
|
POSIX_ACL_USER_OBJ = 1,
|
||||||
POSIX_ACL_USER = 2,
|
POSIX_ACL_USER = 2,
|
||||||
POSIX_ACL_GROUP_OBJ = 4,
|
POSIX_ACL_GROUP_OBJ = 4,
|
||||||
@ -204,7 +216,8 @@ enum {
|
|||||||
* Posix permissions, cpu-endian 16 bits
|
* Posix permissions, cpu-endian 16 bits
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
POSIX_PERM_X = 1,
|
POSIX_PERM_X = 1,
|
||||||
POSIX_PERM_W = 2,
|
POSIX_PERM_W = 2,
|
||||||
POSIX_PERM_R = 4,
|
POSIX_PERM_R = 4,
|
||||||
@ -310,7 +323,8 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni,
|
|||||||
|
|
||||||
#define MAGIC_API 0x09042009
|
#define MAGIC_API 0x09042009
|
||||||
|
|
||||||
struct SECURITY_API {
|
struct SECURITY_API
|
||||||
|
{
|
||||||
u32 magic;
|
u32 magic;
|
||||||
struct SECURITY_CONTEXT security;
|
struct SECURITY_CONTEXT security;
|
||||||
struct PERMISSIONS_CACHE *seccache;
|
struct PERMISSIONS_CACHE *seccache;
|
||||||
|
@ -92,7 +92,8 @@ typedef sle64 leLSN;
|
|||||||
/**
|
/**
|
||||||
* enum BOOL - These are just to make the code more readable...
|
* enum BOOL - These are just to make the code more readable...
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
FALSE = 0,
|
FALSE = 0,
|
||||||
#endif
|
#endif
|
||||||
@ -118,7 +119,8 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* enum IGNORE_CASE_BOOL -
|
* enum IGNORE_CASE_BOOL -
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
CASE_SENSITIVE = 0,
|
CASE_SENSITIVE = 0,
|
||||||
IGNORE_CASE = 1,
|
IGNORE_CASE = 1,
|
||||||
} IGNORE_CASE_BOOL;
|
} IGNORE_CASE_BOOL;
|
||||||
|
@ -88,7 +88,8 @@ static int nfconvert_utf8 = 1;
|
|||||||
* characters are (in)valid.
|
* characters are (in)valid.
|
||||||
*/
|
*/
|
||||||
#if 0
|
#if 0
|
||||||
static const u8 legal_ansi_char_array[0x40] = {
|
static const u8 legal_ansi_char_array[0x40] =
|
||||||
|
{
|
||||||
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||||
|
|
||||||
@ -158,20 +159,25 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||||||
u16 u1, u2;
|
u16 u1, u2;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
|
if ( !name1 || !name2 || ( ic && ( !upcase || !upcase_len ) ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "ntfs_names_collate received NULL pointer!\n" );
|
ntfs_log_debug( "ntfs_names_collate received NULL pointer!\n" );
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
cnt = min( name1_len, name2_len );
|
cnt = min( name1_len, name2_len );
|
||||||
if (cnt > 0) {
|
if ( cnt > 0 )
|
||||||
if (ic == CASE_SENSITIVE) {
|
{
|
||||||
do {
|
if ( ic == CASE_SENSITIVE )
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
c1 = le16_to_cpu( *name1 );
|
c1 = le16_to_cpu( *name1 );
|
||||||
name1++;
|
name1++;
|
||||||
c2 = le16_to_cpu( *name2 );
|
c2 = le16_to_cpu( *name2 );
|
||||||
name2++;
|
name2++;
|
||||||
} while (--cnt && (c1 == c2));
|
}
|
||||||
|
while ( --cnt && ( c1 == c2 ) );
|
||||||
u1 = c1;
|
u1 = c1;
|
||||||
u2 = c2;
|
u2 = c2;
|
||||||
if ( u1 < upcase_len )
|
if ( u1 < upcase_len )
|
||||||
@ -179,7 +185,8 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||||||
if ( u2 < upcase_len )
|
if ( u2 < upcase_len )
|
||||||
u2 = le16_to_cpu( upcase[u2] );
|
u2 = le16_to_cpu( upcase[u2] );
|
||||||
if ( ( u1 == u2 ) && cnt )
|
if ( ( u1 == u2 ) && cnt )
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
u1 = le16_to_cpu( *name1 );
|
u1 = le16_to_cpu( *name1 );
|
||||||
name1++;
|
name1++;
|
||||||
u2 = le16_to_cpu( *name2 );
|
u2 = le16_to_cpu( *name2 );
|
||||||
@ -188,7 +195,8 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||||||
u1 = le16_to_cpu( upcase[u1] );
|
u1 = le16_to_cpu( upcase[u1] );
|
||||||
if ( u2 < upcase_len )
|
if ( u2 < upcase_len )
|
||||||
u2 = le16_to_cpu( upcase[u2] );
|
u2 = le16_to_cpu( upcase[u2] );
|
||||||
} while ((u1 == u2) && --cnt);
|
}
|
||||||
|
while ( ( u1 == u2 ) && --cnt );
|
||||||
if ( u1 < u2 )
|
if ( u1 < u2 )
|
||||||
return -1;
|
return -1;
|
||||||
if ( u1 > u2 )
|
if ( u1 > u2 )
|
||||||
@ -201,8 +209,11 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||||||
return -1;
|
return -1;
|
||||||
if ( c1 > c2 )
|
if ( c1 > c2 )
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
}
|
||||||
do {
|
else
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
u1 = c1 = le16_to_cpu( *name1 );
|
u1 = c1 = le16_to_cpu( *name1 );
|
||||||
name1++;
|
name1++;
|
||||||
u2 = c2 = le16_to_cpu( *name2 );
|
u2 = c2 = le16_to_cpu( *name2 );
|
||||||
@ -211,7 +222,8 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||||||
u1 = le16_to_cpu( upcase[u1] );
|
u1 = le16_to_cpu( upcase[u1] );
|
||||||
if ( u2 < upcase_len )
|
if ( u2 < upcase_len )
|
||||||
u2 = le16_to_cpu( upcase[u2] );
|
u2 = le16_to_cpu( upcase[u2] );
|
||||||
} while ((u1 == u2) && --cnt);
|
}
|
||||||
|
while ( ( u1 == u2 ) && --cnt );
|
||||||
if ( u1 < u2 )
|
if ( u1 < u2 )
|
||||||
return -1;
|
return -1;
|
||||||
if ( u1 > u2 )
|
if ( u1 > u2 )
|
||||||
@ -221,7 +233,9 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||||||
if ( name1_len > name2_len )
|
if ( name1_len > name2_len )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( name1_len < name2_len )
|
if ( name1_len < name2_len )
|
||||||
return -1;
|
return -1;
|
||||||
if ( name1_len > name2_len )
|
if ( name1_len > name2_len )
|
||||||
@ -250,12 +264,14 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!s1 || !s2) {
|
if ( !s1 || !s2 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "ntfs_wcsncmp() received NULL pointer!\n" );
|
ntfs_log_debug( "ntfs_wcsncmp() received NULL pointer!\n" );
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < n; ++i) {
|
for ( i = 0; i < n; ++i )
|
||||||
|
{
|
||||||
c1 = le16_to_cpu( s1[i] );
|
c1 = le16_to_cpu( s1[i] );
|
||||||
c2 = le16_to_cpu( s2[i] );
|
c2 = le16_to_cpu( s2[i] );
|
||||||
if ( c1 < c2 )
|
if ( c1 < c2 )
|
||||||
@ -293,12 +309,14 @@ int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!s1 || !s2 || !upcase) {
|
if ( !s1 || !s2 || !upcase )
|
||||||
|
{
|
||||||
ntfs_log_debug( "ntfs_wcsncasecmp() received NULL pointer!\n" );
|
ntfs_log_debug( "ntfs_wcsncasecmp() received NULL pointer!\n" );
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < n; ++i) {
|
for ( i = 0; i < n; ++i )
|
||||||
|
{
|
||||||
if ( ( c1 = le16_to_cpu( s1[i] ) ) < upcase_size )
|
if ( ( c1 = le16_to_cpu( s1[i] ) ) < upcase_size )
|
||||||
c1 = le16_to_cpu( upcase[c1] );
|
c1 = le16_to_cpu( upcase[c1] );
|
||||||
if ( ( c2 = le16_to_cpu( s2[i] ) ) < upcase_size )
|
if ( ( c2 = le16_to_cpu( s2[i] ) ) < upcase_size )
|
||||||
@ -329,7 +347,8 @@ u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen)
|
|||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
for (i = 0; i < maxlen; i++) {
|
for ( i = 0; i < maxlen; i++ )
|
||||||
|
{
|
||||||
if ( !le16_to_cpu( s[i] ) )
|
if ( !le16_to_cpu( s[i] ) )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -360,7 +379,8 @@ ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
|
|||||||
|
|
||||||
len = ntfs_ucsnlen( s, maxlen );
|
len = ntfs_ucsnlen( s, maxlen );
|
||||||
dst = ntfs_malloc( ( len + 1 ) * sizeof( ntfschar ) );
|
dst = ntfs_malloc( ( len + 1 ) * sizeof( ntfschar ) );
|
||||||
if (dst) {
|
if ( dst )
|
||||||
|
{
|
||||||
memcpy( dst, s, len * sizeof( ntfschar ) );
|
memcpy( dst, s, len * sizeof( ntfschar ) );
|
||||||
dst[len] = cpu_to_le16( L'\0' );
|
dst[len] = cpu_to_le16( L'\0' );
|
||||||
}
|
}
|
||||||
@ -458,16 +478,20 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
|
|||||||
BOOL surrog;
|
BOOL surrog;
|
||||||
|
|
||||||
surrog = FALSE;
|
surrog = FALSE;
|
||||||
for (i = 0; i < ins_len && ins[i]; i++) {
|
for ( i = 0; i < ins_len && ins[i]; i++ )
|
||||||
|
{
|
||||||
unsigned short c = le16_to_cpu( ins[i] );
|
unsigned short c = le16_to_cpu( ins[i] );
|
||||||
if (surrog) {
|
if ( surrog )
|
||||||
if ((c >= 0xdc00) && (c < 0xe000)) {
|
{
|
||||||
|
if ( ( c >= 0xdc00 ) && ( c < 0xe000 ) )
|
||||||
|
{
|
||||||
surrog = FALSE;
|
surrog = FALSE;
|
||||||
count += 4;
|
count += 4;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
} else
|
}
|
||||||
if (c < 0x80)
|
else if ( c < 0x80 )
|
||||||
count++;
|
count++;
|
||||||
else if ( c < 0x800 )
|
else if ( c < 0x800 )
|
||||||
count += 2;
|
count += 2;
|
||||||
@ -483,7 +507,8 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
|
|||||||
count += 3;
|
count += 3;
|
||||||
else
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
if (count > outs_len) {
|
if ( count > outs_len )
|
||||||
|
{
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -531,7 +556,8 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||||||
if ( size < 0 )
|
if ( size < 0 )
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!*outs) {
|
if ( !*outs )
|
||||||
|
{
|
||||||
outs_len = size + 1;
|
outs_len = size + 1;
|
||||||
*outs = ntfs_malloc( outs_len );
|
*outs = ntfs_malloc( outs_len );
|
||||||
if ( !*outs )
|
if ( !*outs )
|
||||||
@ -540,35 +566,49 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||||||
|
|
||||||
t = *outs;
|
t = *outs;
|
||||||
|
|
||||||
for (i = 0; i < ins_len && ins[i]; i++) {
|
for ( i = 0; i < ins_len && ins[i]; i++ )
|
||||||
|
{
|
||||||
unsigned short c = le16_to_cpu( ins[i] );
|
unsigned short c = le16_to_cpu( ins[i] );
|
||||||
/* size not double-checked */
|
/* size not double-checked */
|
||||||
if (halfpair) {
|
if ( halfpair )
|
||||||
if ((c >= 0xdc00) && (c < 0xe000)) {
|
{
|
||||||
|
if ( ( c >= 0xdc00 ) && ( c < 0xe000 ) )
|
||||||
|
{
|
||||||
*t++ = 0xf0 + ( ( ( halfpair + 64 ) >> 8 ) & 7 );
|
*t++ = 0xf0 + ( ( ( halfpair + 64 ) >> 8 ) & 7 );
|
||||||
*t++ = 0x80 + ( ( ( halfpair + 64 ) >> 2 ) & 63 );
|
*t++ = 0x80 + ( ( ( halfpair + 64 ) >> 2 ) & 63 );
|
||||||
*t++ = 0x80 + ( ( c >> 6 ) & 15 ) + ( ( halfpair & 3 ) << 4 );
|
*t++ = 0x80 + ( ( c >> 6 ) & 15 ) + ( ( halfpair & 3 ) << 4 );
|
||||||
*t++ = 0x80 + ( c & 63 );
|
*t++ = 0x80 + ( c & 63 );
|
||||||
halfpair = 0;
|
halfpair = 0;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (c < 0x80) {
|
}
|
||||||
|
else if ( c < 0x80 )
|
||||||
|
{
|
||||||
*t++ = c;
|
*t++ = c;
|
||||||
} else {
|
}
|
||||||
if (c < 0x800) {
|
else
|
||||||
|
{
|
||||||
|
if ( c < 0x800 )
|
||||||
|
{
|
||||||
*t++ = ( 0xc0 | ( ( c >> 6 ) & 0x3f ) );
|
*t++ = ( 0xc0 | ( ( c >> 6 ) & 0x3f ) );
|
||||||
*t++ = 0x80 | ( c & 0x3f );
|
*t++ = 0x80 | ( c & 0x3f );
|
||||||
} else if (c < 0xd800) {
|
}
|
||||||
|
else if ( c < 0xd800 )
|
||||||
|
{
|
||||||
*t++ = 0xe0 | ( c >> 12 );
|
*t++ = 0xe0 | ( c >> 12 );
|
||||||
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
|
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
|
||||||
*t++ = 0x80 | ( c & 0x3f );
|
*t++ = 0x80 | ( c & 0x3f );
|
||||||
} else if (c < 0xdc00)
|
}
|
||||||
|
else if ( c < 0xdc00 )
|
||||||
halfpair = c;
|
halfpair = c;
|
||||||
else if (c >= 0xe000) {
|
else if ( c >= 0xe000 )
|
||||||
|
{
|
||||||
*t++ = 0xe0 | ( c >> 12 );
|
*t++ = 0xe0 | ( c >> 12 );
|
||||||
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
|
*t++ = 0x80 | ( ( c >> 6 ) & 0x3f );
|
||||||
*t++ = 0x80 | ( c & 0x3f );
|
*t++ = 0x80 | ( c & 0x3f );
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -576,17 +616,21 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||||||
|
|
||||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||||
#ifdef ENABLE_NFCONV
|
#ifdef ENABLE_NFCONV
|
||||||
if(nfconvert_utf8 && (t - *outs) > 0) {
|
if ( nfconvert_utf8 && ( t - *outs ) > 0 )
|
||||||
|
{
|
||||||
char *new_outs = NULL;
|
char *new_outs = NULL;
|
||||||
int new_outs_len = ntfs_macosx_normalize_utf8( *outs, &new_outs, 0 ); // Normalize to decomposed form
|
int new_outs_len = ntfs_macosx_normalize_utf8( *outs, &new_outs, 0 ); // Normalize to decomposed form
|
||||||
if(new_outs_len >= 0 && new_outs != NULL) {
|
if ( new_outs_len >= 0 && new_outs != NULL )
|
||||||
if(original_outs_value != *outs) {
|
{
|
||||||
|
if ( original_outs_value != *outs )
|
||||||
|
{
|
||||||
// We have allocated outs ourselves.
|
// We have allocated outs ourselves.
|
||||||
free( *outs );
|
free( *outs );
|
||||||
*outs = new_outs;
|
*outs = new_outs;
|
||||||
t = *outs + new_outs_len;
|
t = *outs + new_outs_len;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// We need to copy new_outs into the fixed outs buffer.
|
// We need to copy new_outs into the fixed outs buffer.
|
||||||
memset( *outs, 0, original_outs_len );
|
memset( *outs, 0, original_outs_len );
|
||||||
strncpy( *outs, new_outs, original_outs_len - 1 );
|
strncpy( *outs, new_outs, original_outs_len - 1 );
|
||||||
@ -594,7 +638,8 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||||||
free( new_outs );
|
free( new_outs );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "Failed to normalize NTFS string to UTF-8 NFD: %s\n", *outs );
|
ntfs_log_error( "Failed to normalize NTFS string to UTF-8 NFD: %s\n", *outs );
|
||||||
ntfs_log_error( " new_outs=0x%p\n", new_outs );
|
ntfs_log_error( " new_outs=0x%p\n", new_outs );
|
||||||
ntfs_log_error( " new_outs_len=%d\n", new_outs_len );
|
ntfs_log_error( " new_outs_len=%d\n", new_outs_len );
|
||||||
@ -626,11 +671,14 @@ static int utf8_to_utf16_size(const char *s)
|
|||||||
unsigned int byte;
|
unsigned int byte;
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
while ((byte = *((const unsigned char *)s++))) {
|
while ( ( byte = *( ( const unsigned char * )s++ ) ) )
|
||||||
|
{
|
||||||
if ( ++count >= PATH_MAX )
|
if ( ++count >= PATH_MAX )
|
||||||
goto fail;
|
goto fail;
|
||||||
if (byte >= 0xc0) {
|
if ( byte >= 0xc0 )
|
||||||
if (byte >= 0xF5) {
|
{
|
||||||
|
if ( byte >= 0xF5 )
|
||||||
|
{
|
||||||
errno = EILSEQ;
|
errno = EILSEQ;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -644,7 +692,8 @@ static int utf8_to_utf16_size(const char *s)
|
|||||||
s++;
|
s++;
|
||||||
if ( !*s )
|
if ( !*s )
|
||||||
break;
|
break;
|
||||||
if (byte >= 0xF0) {
|
if ( byte >= 0xF0 )
|
||||||
|
{
|
||||||
s++;
|
s++;
|
||||||
if ( ++count >= PATH_MAX )
|
if ( ++count >= PATH_MAX )
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -670,25 +719,37 @@ static int utf8_to_unicode(u32 *wc, const char *s)
|
|||||||
unsigned int byte = *( ( const unsigned char * )s );
|
unsigned int byte = *( ( const unsigned char * )s );
|
||||||
|
|
||||||
/* single byte */
|
/* single byte */
|
||||||
if (byte == 0) {
|
if ( byte == 0 )
|
||||||
|
{
|
||||||
*wc = ( u32 ) 0;
|
*wc = ( u32 ) 0;
|
||||||
return 0;
|
return 0;
|
||||||
} else if (byte < 0x80) {
|
}
|
||||||
|
else if ( byte < 0x80 )
|
||||||
|
{
|
||||||
*wc = ( u32 ) byte;
|
*wc = ( u32 ) byte;
|
||||||
return 1;
|
return 1;
|
||||||
/* double byte */
|
/* double byte */
|
||||||
} else if (byte < 0xc2) {
|
}
|
||||||
|
else if ( byte < 0xc2 )
|
||||||
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (byte < 0xE0) {
|
}
|
||||||
if ((s[1] & 0xC0) == 0x80) {
|
else if ( byte < 0xE0 )
|
||||||
|
{
|
||||||
|
if ( ( s[1] & 0xC0 ) == 0x80 )
|
||||||
|
{
|
||||||
*wc = ( ( u32 )( byte & 0x1F ) << 6 )
|
*wc = ( ( u32 )( byte & 0x1F ) << 6 )
|
||||||
| ( ( u32 )( s[1] & 0x3F ) );
|
| ( ( u32 )( s[1] & 0x3F ) );
|
||||||
return 2;
|
return 2;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
/* three-byte */
|
/* three-byte */
|
||||||
} else if (byte < 0xF0) {
|
}
|
||||||
if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)) {
|
else if ( byte < 0xF0 )
|
||||||
|
{
|
||||||
|
if ( ( ( s[1] & 0xC0 ) == 0x80 ) && ( ( s[2] & 0xC0 ) == 0x80 ) )
|
||||||
|
{
|
||||||
*wc = ( ( u32 )( byte & 0x0F ) << 12 )
|
*wc = ( ( u32 )( byte & 0x0F ) << 12 )
|
||||||
| ( ( u32 )( s[1] & 0x3F ) << 6 )
|
| ( ( u32 )( s[1] & 0x3F ) << 6 )
|
||||||
| ( ( u32 )( s[2] & 0x3F ) );
|
| ( ( u32 )( s[2] & 0x3F ) );
|
||||||
@ -705,9 +766,12 @@ static int utf8_to_unicode(u32 *wc, const char *s)
|
|||||||
}
|
}
|
||||||
goto fail;
|
goto fail;
|
||||||
/* four-byte */
|
/* four-byte */
|
||||||
} else if (byte < 0xF5) {
|
}
|
||||||
|
else if ( byte < 0xF5 )
|
||||||
|
{
|
||||||
if ( ( ( s[1] & 0xC0 ) == 0x80 ) && ( ( s[2] & 0xC0 ) == 0x80 )
|
if ( ( ( s[1] & 0xC0 ) == 0x80 ) && ( ( s[2] & 0xC0 ) == 0x80 )
|
||||||
&& ((s[3] & 0xC0) == 0x80)) {
|
&& ( ( s[3] & 0xC0 ) == 0x80 ) )
|
||||||
|
{
|
||||||
*wc = ( ( u32 )( byte & 0x07 ) << 18 )
|
*wc = ( ( u32 )( byte & 0x07 ) << 18 )
|
||||||
| ( ( u32 )( s[1] & 0x3F ) << 12 )
|
| ( ( u32 )( s[1] & 0x3F ) << 12 )
|
||||||
| ( ( u32 )( s[2] & 0x3F ) << 6 )
|
| ( ( u32 )( s[2] & 0x3F ) << 6 )
|
||||||
@ -736,7 +800,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
|||||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||||
#ifdef ENABLE_NFCONV
|
#ifdef ENABLE_NFCONV
|
||||||
char *new_ins = NULL;
|
char *new_ins = NULL;
|
||||||
if(nfconvert_utf8) {
|
if ( nfconvert_utf8 )
|
||||||
|
{
|
||||||
int new_ins_len;
|
int new_ins_len;
|
||||||
new_ins_len = ntfs_macosx_normalize_utf8( ins, &new_ins, 1 ); // Normalize to composed form
|
new_ins_len = ntfs_macosx_normalize_utf8( ins, &new_ins, 1 ); // Normalize to composed form
|
||||||
if ( new_ins_len >= 0 )
|
if ( new_ins_len >= 0 )
|
||||||
@ -757,7 +822,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
allocated = FALSE;
|
allocated = FALSE;
|
||||||
if (!*outs) {
|
if ( !*outs )
|
||||||
|
{
|
||||||
*outs = ntfs_malloc( ( shorts + 1 ) * sizeof( ntfschar ) );
|
*outs = ntfs_malloc( ( shorts + 1 ) * sizeof( ntfschar ) );
|
||||||
if ( !*outs )
|
if ( !*outs )
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -766,12 +832,16 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
|||||||
|
|
||||||
outpos = *outs;
|
outpos = *outs;
|
||||||
|
|
||||||
while(1) {
|
while ( 1 )
|
||||||
|
{
|
||||||
int m = utf8_to_unicode( &wc, t );
|
int m = utf8_to_unicode( &wc, t );
|
||||||
if (m <= 0) {
|
if ( m <= 0 )
|
||||||
if (m < 0) {
|
{
|
||||||
|
if ( m < 0 )
|
||||||
|
{
|
||||||
/* do not leave space allocated if failed */
|
/* do not leave space allocated if failed */
|
||||||
if (allocated) {
|
if ( allocated )
|
||||||
|
{
|
||||||
free( *outs );
|
free( *outs );
|
||||||
*outs = ( ntfschar* )NULL;
|
*outs = ( ntfschar* )NULL;
|
||||||
}
|
}
|
||||||
@ -782,7 +852,8 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
|||||||
}
|
}
|
||||||
if ( wc < 0x10000 )
|
if ( wc < 0x10000 )
|
||||||
*outpos++ = cpu_to_le16( wc );
|
*outpos++ = cpu_to_le16( wc );
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
wc -= 0x10000;
|
wc -= 0x10000;
|
||||||
*outpos++ = cpu_to_le16( ( wc >> 10 ) + 0xd800 );
|
*outpos++ = cpu_to_le16( ( wc >> 10 ) + 0xd800 );
|
||||||
*outpos++ = cpu_to_le16( ( wc & 0x3ff ) + 0xdc00 );
|
*outpos++ = cpu_to_le16( ( wc & 0x3ff ) + 0xdc00 );
|
||||||
@ -837,19 +908,22 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
|||||||
mbstate_t mbstate;
|
mbstate_t mbstate;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!ins || !outs) {
|
if ( !ins || !outs )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mbs = *outs;
|
mbs = *outs;
|
||||||
mbs_len = outs_len;
|
mbs_len = outs_len;
|
||||||
if (mbs && !mbs_len) {
|
if ( mbs && !mbs_len )
|
||||||
|
{
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( use_utf8 )
|
if ( use_utf8 )
|
||||||
return ntfs_utf16_to_utf8( ins, ins_len, outs, outs_len );
|
return ntfs_utf16_to_utf8( ins, ins_len, outs, outs_len );
|
||||||
if (!mbs) {
|
if ( !mbs )
|
||||||
|
{
|
||||||
mbs_len = ( ins_len + 1 ) * MB_CUR_MAX;
|
mbs_len = ( ins_len + 1 ) * MB_CUR_MAX;
|
||||||
mbs = ntfs_malloc( mbs_len );
|
mbs = ntfs_malloc( mbs_len );
|
||||||
if ( !mbs )
|
if ( !mbs )
|
||||||
@ -860,11 +934,14 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
|||||||
#else
|
#else
|
||||||
wctomb( NULL, 0 );
|
wctomb( NULL, 0 );
|
||||||
#endif
|
#endif
|
||||||
for (i = o = 0; i < ins_len; i++) {
|
for ( i = o = 0; i < ins_len; i++ )
|
||||||
|
{
|
||||||
/* Reallocate memory if necessary or abort. */
|
/* Reallocate memory if necessary or abort. */
|
||||||
if ((int)(o + MB_CUR_MAX) > mbs_len) {
|
if ( ( int )( o + MB_CUR_MAX ) > mbs_len )
|
||||||
|
{
|
||||||
char *tc;
|
char *tc;
|
||||||
if (mbs == *outs) {
|
if ( mbs == *outs )
|
||||||
|
{
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -888,7 +965,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
|||||||
#endif
|
#endif
|
||||||
if ( cnt == -1 )
|
if ( cnt == -1 )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
if (cnt <= 0) {
|
if ( cnt <= 0 )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Eeek. cnt <= 0, cnt = %i\n", cnt );
|
ntfs_log_debug( "Eeek. cnt <= 0, cnt = %i\n", cnt );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -897,7 +975,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
|||||||
}
|
}
|
||||||
#ifdef HAVE_MBSINIT
|
#ifdef HAVE_MBSINIT
|
||||||
/* Make sure we are back in the initial state. */
|
/* Make sure we are back in the initial state. */
|
||||||
if (!mbsinit(&mbstate)) {
|
if ( !mbsinit( &mbstate ) )
|
||||||
|
{
|
||||||
ntfs_log_debug( "Eeek. mbstate not in initial state!\n" );
|
ntfs_log_debug( "Eeek. mbstate not in initial state!\n" );
|
||||||
errno = EILSEQ;
|
errno = EILSEQ;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -909,7 +988,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
|||||||
*outs = mbs;
|
*outs = mbs;
|
||||||
return o;
|
return o;
|
||||||
err_out:
|
err_out:
|
||||||
if (mbs != *outs) {
|
if ( mbs != *outs )
|
||||||
|
{
|
||||||
int eo = errno;
|
int eo = errno;
|
||||||
free( mbs );
|
free( mbs );
|
||||||
errno = eo;
|
errno = eo;
|
||||||
@ -950,7 +1030,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
|||||||
mbstate_t mbstate;
|
mbstate_t mbstate;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!ins || !outs) {
|
if ( !ins || !outs )
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -966,7 +1047,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
|||||||
memset( &mbstate, 0, sizeof( mbstate ) );
|
memset( &mbstate, 0, sizeof( mbstate ) );
|
||||||
ins_len = mbsrtowcs( NULL, ( const char ** ) & s, 0, &mbstate );
|
ins_len = mbsrtowcs( NULL, ( const char ** ) & s, 0, &mbstate );
|
||||||
#ifdef __CYGWIN32__
|
#ifdef __CYGWIN32__
|
||||||
if (!ins_len && *ins) {
|
if ( !ins_len && *ins )
|
||||||
|
{
|
||||||
/* Older Cygwin had broken mbsrtowcs() implementation. */
|
/* Older Cygwin had broken mbsrtowcs() implementation. */
|
||||||
ins_len = strlen( ins );
|
ins_len = strlen( ins );
|
||||||
}
|
}
|
||||||
@ -980,9 +1062,11 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
|||||||
if ( ins_len == -1 )
|
if ( ins_len == -1 )
|
||||||
return ins_len;
|
return ins_len;
|
||||||
#ifdef HAVE_MBSINIT
|
#ifdef HAVE_MBSINIT
|
||||||
if ((s != ins) || !mbsinit(&mbstate)) {
|
if ( ( s != ins ) || !mbsinit( &mbstate ) )
|
||||||
|
{
|
||||||
#else
|
#else
|
||||||
if (s != ins) {
|
if ( s != ins )
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
errno = EILSEQ;
|
errno = EILSEQ;
|
||||||
return -1;
|
return -1;
|
||||||
@ -998,9 +1082,11 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
|||||||
#else
|
#else
|
||||||
mbtowc( NULL, NULL, 0 );
|
mbtowc( NULL, NULL, 0 );
|
||||||
#endif
|
#endif
|
||||||
for (i = o = cnt = 0; i < ins_size; i += cnt, o++) {
|
for ( i = o = cnt = 0; i < ins_size; i += cnt, o++ )
|
||||||
|
{
|
||||||
/* Reallocate memory if necessary. */
|
/* Reallocate memory if necessary. */
|
||||||
if (o >= ucs_len) {
|
if ( o >= ucs_len )
|
||||||
|
{
|
||||||
ntfschar *tc;
|
ntfschar *tc;
|
||||||
ucs_len = ( ucs_len * sizeof( ntfschar ) + 64 ) & ~63;
|
ucs_len = ( ucs_len * sizeof( ntfschar ) + 64 ) & ~63;
|
||||||
tc = realloc( ucs, ucs_len );
|
tc = realloc( ucs, ucs_len );
|
||||||
@ -1019,14 +1105,16 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
|||||||
break;
|
break;
|
||||||
if ( cnt == -1 )
|
if ( cnt == -1 )
|
||||||
goto err_out;
|
goto err_out;
|
||||||
if (cnt < -1) {
|
if ( cnt < -1 )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Eeek. cnt = %i\n", cnt );
|
ntfs_log_trace( "Eeek. cnt = %i\n", cnt );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* Make sure we are not overflowing the NTFS Unicode set. */
|
/* Make sure we are not overflowing the NTFS Unicode set. */
|
||||||
if ( ( unsigned long )wc >= ( unsigned long )( 1 <<
|
if ( ( unsigned long )wc >= ( unsigned long )( 1 <<
|
||||||
(8 * sizeof(ntfschar)))) {
|
( 8 * sizeof( ntfschar ) ) ) )
|
||||||
|
{
|
||||||
errno = EILSEQ;
|
errno = EILSEQ;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -1035,7 +1123,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
|||||||
}
|
}
|
||||||
#ifdef HAVE_MBSINIT
|
#ifdef HAVE_MBSINIT
|
||||||
/* Make sure we are back in the initial state. */
|
/* Make sure we are back in the initial state. */
|
||||||
if (!mbsinit(&mbstate)) {
|
if ( !mbsinit( &mbstate ) )
|
||||||
|
{
|
||||||
ntfs_log_trace( "Eeek. mbstate not in initial state!\n" );
|
ntfs_log_trace( "Eeek. mbstate not in initial state!\n" );
|
||||||
errno = EILSEQ;
|
errno = EILSEQ;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -1069,24 +1158,32 @@ char *ntfs_uppercase_mbs(const char *low,
|
|||||||
|
|
||||||
size = strlen( low );
|
size = strlen( low );
|
||||||
upp = ( char* )ntfs_malloc( 3 * size + 1 );
|
upp = ( char* )ntfs_malloc( 3 * size + 1 );
|
||||||
if (upp) {
|
if ( upp )
|
||||||
|
{
|
||||||
s = low;
|
s = low;
|
||||||
t = upp;
|
t = upp;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
n = utf8_to_unicode( &wc, s );
|
n = utf8_to_unicode( &wc, s );
|
||||||
if (n > 0) {
|
if ( n > 0 )
|
||||||
|
{
|
||||||
if ( wc < upcase_size )
|
if ( wc < upcase_size )
|
||||||
wc = le16_to_cpu( upcase[wc] );
|
wc = le16_to_cpu( upcase[wc] );
|
||||||
if ( wc < 0x80 )
|
if ( wc < 0x80 )
|
||||||
*t++ = wc;
|
*t++ = wc;
|
||||||
else if (wc < 0x800) {
|
else if ( wc < 0x800 )
|
||||||
|
{
|
||||||
*t++ = ( 0xc0 | ( ( wc >> 6 ) & 0x3f ) );
|
*t++ = ( 0xc0 | ( ( wc >> 6 ) & 0x3f ) );
|
||||||
*t++ = 0x80 | ( wc & 0x3f );
|
*t++ = 0x80 | ( wc & 0x3f );
|
||||||
} else if (wc < 0x10000) {
|
}
|
||||||
|
else if ( wc < 0x10000 )
|
||||||
|
{
|
||||||
*t++ = 0xe0 | ( wc >> 12 );
|
*t++ = 0xe0 | ( wc >> 12 );
|
||||||
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
|
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
|
||||||
*t++ = 0x80 | ( wc & 0x3f );
|
*t++ = 0x80 | ( wc & 0x3f );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
*t++ = 0xf0 | ( ( wc >> 18 ) & 7 );
|
*t++ = 0xf0 | ( ( wc >> 18 ) & 7 );
|
||||||
*t++ = 0x80 | ( ( wc >> 12 ) & 63 );
|
*t++ = 0x80 | ( ( wc >> 12 ) & 63 );
|
||||||
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
|
*t++ = 0x80 | ( ( wc >> 6 ) & 0x3f );
|
||||||
@ -1094,8 +1191,10 @@ char *ntfs_uppercase_mbs(const char *low,
|
|||||||
}
|
}
|
||||||
s += n;
|
s += n;
|
||||||
}
|
}
|
||||||
} while (n > 0);
|
}
|
||||||
if (n < 0) {
|
while ( n > 0 );
|
||||||
|
if ( n < 0 )
|
||||||
|
{
|
||||||
free( upp );
|
free( upp );
|
||||||
upp = ( char* )NULL;
|
upp = ( char* )NULL;
|
||||||
errno = EILSEQ;
|
errno = EILSEQ;
|
||||||
@ -1117,7 +1216,8 @@ char *ntfs_uppercase_mbs(const char *low,
|
|||||||
*/
|
*/
|
||||||
void ntfs_upcase_table_build( ntfschar *uc, u32 uc_len )
|
void ntfs_upcase_table_build( ntfschar *uc, u32 uc_len )
|
||||||
{
|
{
|
||||||
static int uc_run_table[][3] = { /* Start, End, Add */
|
static int uc_run_table[][3] = /* Start, End, Add */
|
||||||
|
{
|
||||||
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
|
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
|
||||||
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
||||||
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
|
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
|
||||||
@ -1133,7 +1233,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
|||||||
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
|
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
static int uc_dup_table[][2] = { /* Start, End */
|
static int uc_dup_table[][2] = /* Start, End */
|
||||||
|
{
|
||||||
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
|
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
|
||||||
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
|
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
|
||||||
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
|
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
|
||||||
@ -1142,7 +1243,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
|||||||
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
|
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
static int uc_byte_table[][2] = { /* Offset, Value */
|
static int uc_byte_table[][2] = /* Offset, Value */
|
||||||
|
{
|
||||||
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
|
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
|
||||||
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
|
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
|
||||||
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
|
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
|
||||||
@ -1162,7 +1264,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
|||||||
uc_len = 65536;
|
uc_len = 65536;
|
||||||
for ( i = 0; ( u32 )i < uc_len; i++ )
|
for ( i = 0; ( u32 )i < uc_len; i++ )
|
||||||
uc[i] = cpu_to_le16( i );
|
uc[i] = cpu_to_le16( i );
|
||||||
for (r = 0; uc_run_table[r][0]; r++) {
|
for ( r = 0; uc_run_table[r][0]; r++ )
|
||||||
|
{
|
||||||
off = uc_run_table[r][2];
|
off = uc_run_table[r][2];
|
||||||
for ( i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++ )
|
for ( i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++ )
|
||||||
uc[i] = cpu_to_le16( i + off );
|
uc[i] = cpu_to_le16( i + off );
|
||||||
@ -1170,7 +1273,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
|||||||
for ( r = 0; uc_dup_table[r][0]; r++ )
|
for ( r = 0; uc_dup_table[r][0]; r++ )
|
||||||
for ( i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2 )
|
for ( i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2 )
|
||||||
uc[i + 1] = cpu_to_le16( i );
|
uc[i + 1] = cpu_to_le16( i );
|
||||||
for (r = 0; uc_byte_table[r][0]; r++) {
|
for ( r = 0; uc_byte_table[r][0]; r++ )
|
||||||
|
{
|
||||||
k = uc_byte_table[r][1];
|
k = uc_byte_table[r][1];
|
||||||
uc[uc_byte_table[r][0]] = cpu_to_le16( k );
|
uc[uc_byte_table[r][0]] = cpu_to_le16( k );
|
||||||
}
|
}
|
||||||
@ -1195,15 +1299,18 @@ ntfschar *ntfs_locase_table_build(const ntfschar *uc, u32 uc_cnt)
|
|||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
lc = ( ntfschar* )ntfs_malloc( uc_cnt * sizeof( ntfschar ) );
|
lc = ( ntfschar* )ntfs_malloc( uc_cnt * sizeof( ntfschar ) );
|
||||||
if (lc) {
|
if ( lc )
|
||||||
|
{
|
||||||
for ( i = 0; i < uc_cnt; i++ )
|
for ( i = 0; i < uc_cnt; i++ )
|
||||||
lc[i] = cpu_to_le16( i );
|
lc[i] = cpu_to_le16( i );
|
||||||
for (i=0; i<uc_cnt; i++) {
|
for ( i = 0; i < uc_cnt; i++ )
|
||||||
|
{
|
||||||
upp = le16_to_cpu( uc[i] );
|
upp = le16_to_cpu( uc[i] );
|
||||||
if ( ( upp != i ) && ( upp < uc_cnt ) )
|
if ( ( upp != i ) && ( upp < uc_cnt ) )
|
||||||
lc[upp] = cpu_to_le16( i );
|
lc[upp] = cpu_to_le16( i );
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ntfs_log_error( "Could not build the locase table\n" );
|
ntfs_log_error( "Could not build the locase table\n" );
|
||||||
return ( lc );
|
return ( lc );
|
||||||
}
|
}
|
||||||
@ -1229,16 +1336,19 @@ ntfschar *ntfs_str2ucs(const char *s, int *len)
|
|||||||
{
|
{
|
||||||
ntfschar *ucs = NULL;
|
ntfschar *ucs = NULL;
|
||||||
|
|
||||||
if (s && ((*len = ntfs_mbstoucs(s, &ucs)) == -1)) {
|
if ( s && ( ( *len = ntfs_mbstoucs( s, &ucs ) ) == -1 ) )
|
||||||
|
{
|
||||||
ntfs_log_perror( "Couldn't convert '%s' to Unicode", s );
|
ntfs_log_perror( "Couldn't convert '%s' to Unicode", s );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (*len > NTFS_MAX_NAME_LEN) {
|
if ( *len > NTFS_MAX_NAME_LEN )
|
||||||
|
{
|
||||||
free( ucs );
|
free( ucs );
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!ucs || !*len) {
|
if ( !ucs || !*len )
|
||||||
|
{
|
||||||
ucs = AT_UNNAMED;
|
ucs = AT_UNNAMED;
|
||||||
*len = 0;
|
*len = 0;
|
||||||
}
|
}
|
||||||
@ -1282,7 +1392,8 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
|||||||
forbidden = ( len == 0 )
|
forbidden = ( len == 0 )
|
||||||
|| ( le16_to_cpu( name[len-1] ) == ' ' )
|
|| ( le16_to_cpu( name[len-1] ) == ' ' )
|
||||||
|| ( le16_to_cpu( name[len-1] ) == '.' );
|
|| ( le16_to_cpu( name[len-1] ) == '.' );
|
||||||
for (i=0; i<len; i++) {
|
for ( i = 0; i < len; i++ )
|
||||||
|
{
|
||||||
ch = le16_to_cpu( name[i] );
|
ch = le16_to_cpu( name[i] );
|
||||||
if ( ( ch < 0x20 )
|
if ( ( ch < 0x20 )
|
||||||
|| ( ( ch < 0x40 )
|
|| ( ( ch < 0x40 )
|
||||||
@ -1314,7 +1425,8 @@ BOOL ntfs_collapsible_chars(ntfs_volume *vol,
|
|||||||
|
|
||||||
collapsible = shortlen == longlen;
|
collapsible = shortlen == longlen;
|
||||||
if ( collapsible )
|
if ( collapsible )
|
||||||
for (i=0; i<shortlen; i++) {
|
for ( i = 0; i < shortlen; i++ )
|
||||||
|
{
|
||||||
ch = le16_to_cpu( longname[i] );
|
ch = le16_to_cpu( longname[i] );
|
||||||
if ( ( ch >= vol->upcase_len )
|
if ( ( ch >= vol->upcase_len )
|
||||||
|| ( ( shortname[i] != longname[i] )
|
|| ( ( shortname[i] != longname[i] )
|
||||||
@ -1335,10 +1447,10 @@ int ntfs_set_char_encoding(const char *locale)
|
|||||||
if ( !locale || strstr( locale, "utf8" ) || strstr( locale, "UTF8" )
|
if ( !locale || strstr( locale, "utf8" ) || strstr( locale, "UTF8" )
|
||||||
|| strstr( locale, "utf-8" ) || strstr( locale, "UTF-8" ) )
|
|| strstr( locale, "utf-8" ) || strstr( locale, "UTF-8" ) )
|
||||||
use_utf8 = 1;
|
use_utf8 = 1;
|
||||||
else
|
else if ( setlocale( LC_ALL, locale ) )
|
||||||
if (setlocale(LC_ALL, locale))
|
|
||||||
use_utf8 = 0;
|
use_utf8 = 0;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
ntfs_log_error( "Invalid locale, encoding to UTF-8\n" );
|
ntfs_log_error( "Invalid locale, encoding to UTF-8\n" );
|
||||||
use_utf8 = 1;
|
use_utf8 = 1;
|
||||||
}
|
}
|
||||||
@ -1347,9 +1459,11 @@ int ntfs_set_char_encoding(const char *locale)
|
|||||||
|
|
||||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||||
|
|
||||||
int ntfs_macosx_normalize_filenames(int normalize) {
|
int ntfs_macosx_normalize_filenames( int normalize )
|
||||||
|
{
|
||||||
#ifdef ENABLE_NFCONV
|
#ifdef ENABLE_NFCONV
|
||||||
if(normalize == 0 || normalize == 1) {
|
if ( normalize == 0 || normalize == 1 )
|
||||||
|
{
|
||||||
nfconvert_utf8 = normalize;
|
nfconvert_utf8 = normalize;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1361,7 +1475,8 @@ int ntfs_macosx_normalize_filenames(int normalize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ntfs_macosx_normalize_utf8( const char *utf8_string, char **target,
|
int ntfs_macosx_normalize_utf8( const char *utf8_string, char **target,
|
||||||
int composed) {
|
int composed )
|
||||||
|
{
|
||||||
#ifdef ENABLE_NFCONV
|
#ifdef ENABLE_NFCONV
|
||||||
/* For this code to compile, the CoreFoundation framework must be fed to the linker. */
|
/* For this code to compile, the CoreFoundation framework must be fed to the linker. */
|
||||||
CFStringRef cfSourceString;
|
CFStringRef cfSourceString;
|
||||||
@ -1373,7 +1488,8 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
|
|||||||
|
|
||||||
/* Convert the UTF-8 string to a CFString. */
|
/* Convert the UTF-8 string to a CFString. */
|
||||||
cfSourceString = CFStringCreateWithCString( kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8 );
|
cfSourceString = CFStringCreateWithCString( kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8 );
|
||||||
if(cfSourceString == NULL) {
|
if ( cfSourceString == NULL )
|
||||||
|
{
|
||||||
ntfs_log_error( "CFStringCreateWithCString failed!\n" );
|
ntfs_log_error( "CFStringCreateWithCString failed!\n" );
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
@ -1381,7 +1497,8 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
|
|||||||
/* Create a mutable string from cfSourceString that we are free to modify. */
|
/* Create a mutable string from cfSourceString that we are free to modify. */
|
||||||
cfMutableString = CFStringCreateMutableCopy( kCFAllocatorDefault, 0, cfSourceString );
|
cfMutableString = CFStringCreateMutableCopy( kCFAllocatorDefault, 0, cfSourceString );
|
||||||
CFRelease( cfSourceString ); /* End-of-life. */
|
CFRelease( cfSourceString ); /* End-of-life. */
|
||||||
if(cfMutableString == NULL) {
|
if ( cfMutableString == NULL )
|
||||||
|
{
|
||||||
ntfs_log_error( "CFStringCreateMutableCopy failed!\n" );
|
ntfs_log_error( "CFStringCreateMutableCopy failed!\n" );
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
@ -1391,13 +1508,16 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
|
|||||||
|
|
||||||
/* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */
|
/* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */
|
||||||
rangeToProcess = CFRangeMake( 0, CFStringGetLength( cfMutableString ) );
|
rangeToProcess = CFRangeMake( 0, CFStringGetLength( cfMutableString ) );
|
||||||
if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength) > 0) {
|
if ( CFStringGetBytes( cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength ) > 0 )
|
||||||
|
{
|
||||||
resultLength = sizeof( char ) * ( requiredBufferLength + 1 );
|
resultLength = sizeof( char ) * ( requiredBufferLength + 1 );
|
||||||
result = ntfs_calloc( resultLength );
|
result = ntfs_calloc( resultLength );
|
||||||
|
|
||||||
if(result != NULL) {
|
if ( result != NULL )
|
||||||
|
{
|
||||||
if ( CFStringGetBytes( cfMutableString, rangeToProcess, kCFStringEncodingUTF8,
|
if ( CFStringGetBytes( cfMutableString, rangeToProcess, kCFStringEncodingUTF8,
|
||||||
0, false, (UInt8*)result, resultLength-1, &requiredBufferLength) <= 0) {
|
0, false, ( UInt8* )result, resultLength - 1, &requiredBufferLength ) <= 0 )
|
||||||
|
{
|
||||||
ntfs_log_error( "Could not perform UTF-8 conversion of normalized CFMutableString.\n" );
|
ntfs_log_error( "Could not perform UTF-8 conversion of normalized CFMutableString.\n" );
|
||||||
free( result );
|
free( result );
|
||||||
result = NULL;
|
result = NULL;
|
||||||
@ -1412,7 +1532,8 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
|
|||||||
|
|
||||||
CFRelease( cfMutableString );
|
CFRelease( cfMutableString );
|
||||||
|
|
||||||
if(result != NULL) {
|
if ( result != NULL )
|
||||||
|
{
|
||||||
*target = result;
|
*target = result;
|
||||||
return resultLength - 1;
|
return resultLength - 1;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user