📄 fs.c
字号:
// Some storage which has been formatted by Windows may not be having the
// table.
//
// Following is the comment from user.
// # Now, I figured out FAT16 filesystem bug that I mentioned at previous
// # mail.
// #
// # The problem is, when formatting disk in Windows with FAT16,
// # sometimes disk has no Master Boot Record, but only have Partition
// # Boot Record. i.e. Disk has only one partition like floppy disk.
// # In this case, skipping MBR and direct reading PBR is needed.
partition = ((((MasterBootRecord *)buffer_ptr)->partition)[ 0 ]).DefaultBootPartition;
if ( (partition & ~0x80) == 0x00 ) // partition table exists
{
fs_type = ((((MasterBootRecord *)buffer_ptr)->partition)[ 0 ]).PartitionType;
start_lba = ((((MasterBootRecord *)buffer_ptr)->partition)[ 0 ]).StartLBASector;
#if BIG_ENDIAN
start_lba = swap32( start_lba );
#endif
// The parttition information gives you the sector (LBA) number which is the starting point
// of valid partition data. Read the first sector of the partition.
// This sector has "PartitionBootRecord (PBR)".
// PBR : PC card standard section 4.1.7.1 (include "Partition entry" information)
storage_read_sector( buffer_ptr, start_lba, 1 );
}
// ## Version 1.2c (to here)
// Setting volume information. It stores size of units, and address of boundaries.
//
// The volume will have logical structure like...
/*
+-----------------------------+ -- 0x00000000
| MasterBootRecord |
+ - - - - - - - - - - - - - - +
| |
| |
+-----------------------------+ -- start of partition : (MasterBootRecord.partition[ 0 ]).StartLBASector
| PartitionBootRecord |
+ - - - - - - - - - - - - - - +
| |
| |
+-----------------------------+ -- start of FAT1 = start of partition + (PartitionBootRecord.BIOS_parameter_block).ReservedSectors
| FAT1 |
| |
| |
+-----------------------------+ -- start of FAT2 = start of FAT1 + (PartitionBootRecord.BIOS_parameter_block).NumFATSectors
| FAT2 |
| |
| |
+-----------------------------+ -- start of RootDirectory = start of FAT2 + (PartitionBootRecord.BIOS_parameter_block).NumFATSectors
| RootDirectory |
| |
| |
| |
+-----------------------------+ -- start of File/Directory data = start of RootDirectory + (PartitionBootRecord.BIOS_parameter_block).RootDirEntries * sizeof( directory_entry )
| File/Directory data |
| |
| |
| |
| |
+ - - - - - - - - - - - - - - + <---
| | |
+ - - - - - + | size of claster = (PartitionBootRecord.BIOS_parameter_block).SectorsPerClustor
| | |
+ - - - - - - - - - - - - - - + <---
| | | size of sector = (PartitionBootRecord.BIOS_parameter_block).BytesPerSector
+ - - - - - + <--- ... This can be get by SCSI command "READ_CAPACITY" command also.
| |
+ - - - - - - - - - - - - - - +
| |
*/
#if BIG_ENDIAN
fs_data_copy( fs_name, buffer_ptr + 0x36, 8 );
#else
fs_data_copy( fs_name, ((PartitionBootRecord *)buffer_ptr)->FileSysType, 8 );
#endif
*(fs_name + 8) = 0;
vpp->file_system = FILE_SYSTEM_UNKNOWN;
if ( str_match( fs_name, "FAT16 ", 8 ) )
vpp->file_system = FILE_SYSTEM_FAT16;
if ( str_match( fs_name, "FAT12 ", 8 ) )
vpp->file_system = FILE_SYSTEM_FAT12;
if ( vpp->file_system == FILE_SYSTEM_UNKNOWN )
{
mprintf( LIGHTGRAY, CONTINUE, "error : Unsupported file system [0x%02X]\r\n", fs_type );
return ( NULL );
}
else
{
#if 0
mprintf( LIGHTRED, CONTINUE, "FILE SYSTEM NAME=\"%s\"\r\n", fs_name );
#endif
}
#if BIG_ENDIAN
vpp->bytes_per_sector = *((unsigned short *)(buffer_ptr + 0xB + 0x00)); // BytesPerSector;
vpp->bytes_per_sector = swap16( vpp->bytes_per_sector );
vpp->sector_per_cluster = *((unsigned char *)(buffer_ptr + 0xB + 0x02)); // SectorsPerClustor;
if ( !vpp->sector_per_cluster )
return ( NULL );
vpp->bytes_per_cluster = vpp->bytes_per_sector * vpp->sector_per_cluster;
vpp->reserved_sectors = *((unsigned short *)(buffer_ptr + 0xB + 0x03)); // ReservedSectors;
vpp->reserved_sectors = swap16( vpp->reserved_sectors );
vpp->number_of_FATs = *((unsigned char *)(buffer_ptr + 0xB + 0x05)); // NumFATs;
vpp->root_directory_entries = *((unsigned short *)(buffer_ptr + 0xB + 0x06)); // RootDirEntries;
vpp->root_directory_entries = swap16( vpp->root_directory_entries );
vpp->total_sectors = *((unsigned short *)(buffer_ptr + 0xB + 0x08)); // TotalSectors;
vpp->total_sectors = swap16( vpp->total_sectors );
vpp->number_of_FAT_sectors = *((unsigned short *)(buffer_ptr + 0xB + 0x0B)); // NumFATSectors;
vpp->number_of_FAT_sectors = swap16( vpp->number_of_FAT_sectors );
if ( !(vpp->total_sectors) )
{
vpp->total_sectors = *((unsigned long *)(buffer_ptr + 0xB + 0x15)); // HugeSectors;
vpp->total_sectors = swap32( vpp->total_sectors );
}
#else
vpp->bytes_per_sector = (((PartitionBootRecord *)buffer_ptr)->BPB).BytesPerSector;
vpp->sector_per_cluster = (((PartitionBootRecord *)buffer_ptr)->BPB).SectorsPerClustor;
if ( !vpp->sector_per_cluster )
return ( NULL );
vpp->bytes_per_cluster = vpp->bytes_per_sector * vpp->sector_per_cluster;
vpp->reserved_sectors = (((PartitionBootRecord *)buffer_ptr)->BPB).ReservedSectors;
vpp->number_of_FATs = (((PartitionBootRecord *)buffer_ptr)->BPB).NumFATs;
vpp->root_directory_entries = (((PartitionBootRecord *)buffer_ptr)->BPB).RootDirEntries;
vpp->number_of_FAT_sectors = (((PartitionBootRecord *)buffer_ptr)->BPB).NumFATSectors;
vpp->total_sectors = (((PartitionBootRecord *)buffer_ptr)->BPB).TotalSectors;
if ( !(vpp->total_sectors) )
vpp->total_sectors = (((PartitionBootRecord *)buffer_ptr)->BPB).HugeSectors;
#endif
free( buffer_ptr );
// The temporary buffer freed.
// The sector size data buffering will not be used further.
vpp->start_sector_FAT1 = start_lba + vpp->reserved_sectors;
vpp->start_sector_FAT2 = vpp->start_sector_FAT1 + vpp->number_of_FAT_sectors;
vpp->start_sector_root_directory = vpp->start_sector_FAT2 + vpp->number_of_FAT_sectors;
vpp->start_sector_claster_region = vpp->start_sector_root_directory + ((sizeof( directory_entry ) * vpp->root_directory_entries) / vpp->bytes_per_sector);
vpp->number_of_clasters = (vpp->total_sectors - vpp->start_sector_claster_region) / vpp->sector_per_cluster;
if ( (sizeof( directory_entry ) * vpp->root_directory_entries) % vpp->bytes_per_sector )
vpp->start_sector_claster_region += 1;
// Allocate FAT cache
if ( vpp->file_system == FILE_SYSTEM_FAT16 )
{
// For FAT16, the FAT would be too big to load whole size.
// At this stage, the driver allocates the memory only.
// The FAT is loaded and stored in sector base when it is used.
if ( NULL == (vpp->FAT_cache = (unsigned short *)malloc( vpp->bytes_per_sector )) )
{
mprintf( LIGHTGRAY, CONTINUE, "error : File system init (malloc 3rd) failed\r\n" );
return ( NULL );
}
}
else if ( vpp->file_system == FILE_SYSTEM_FAT12 )
{
if ( NULL == (vpp->FAT_cache = (unsigned short *)malloc( vpp->bytes_per_sector * vpp->number_of_FAT_sectors )) )
{
mprintf( LIGHTGRAY, CONTINUE, "error : File system init (malloc 3rd) failed\r\n" );
return ( NULL );
}
storage_read_sector( (unsigned char *)(vpp->FAT_cache), vpp->start_sector_FAT1, vpp->number_of_FAT_sectors );
}
vpp->FAT_cached_sector = FAT_CACHE_NOT_VALID;
vpp->FAT_cache_dirty = False;
// Allocate directory cache
if ( NULL == (vpp->dir_cache = (unsigned char *)malloc( vpp->bytes_per_cluster )) )
{
mprintf( LIGHTGRAY, CONTINUE, "error : File system init (malloc 4th) failed\r\n" );
return ( NULL );
}
vpp->dir_cached_sector = DIR_CACHE_NOT_VALID;
// Clear file open entries
for ( i = 0; i < MAX_OPEN_FILES; i++ )
(vpp->opened_FILE_pointer)[ i ] = NULL;
// Set default current directory to root
(vpp->current_dir)[ 0 ] = '/';
(vpp->current_dir)[ 1 ] = 0;
vpp->current_directory_cluster = 0;
// Scratch buffer allocate
if ( g_num_of_fs_client )
{
if ( g_fs_scratch_buffer_size < vpp->bytes_per_cluster )
{
free( g_fs_scratch_buffer_ptr );
if ( NULL == ( g_fs_scratch_buffer_ptr = (unsigned char *)malloc( vpp->bytes_per_cluster ) ) )
{
mprintf( LIGHTGRAY, CONTINUE, "error : File system init (malloc for FS scratch) failed\r\n" );
return ( NULL );
}
g_fs_scratch_buffer_size = vpp->bytes_per_cluster;
}
}
if ( !g_num_of_fs_client )
{
if ( NULL == ( g_fs_scratch_buffer_ptr = (unsigned char *)malloc( vpp->bytes_per_cluster ) ) )
{
mprintf( LIGHTGRAY, CONTINUE, "error : File system init (malloc for FS scratch) failed\r\n" );
return ( NULL );
}
}
g_num_of_fs_client++;
return ( vpp );
}
unsigned char fs_volume_close( volume_param *vpp )
{
unsigned char i;
if ( vpp == NULL )
return ( no_error );
for ( i = 0; i < MAX_OPEN_FILES; i++ )
if ( (vpp->opened_FILE_pointer)[ i ] != NULL )
fs_fclose( (vpp->opened_FILE_pointer)[ i ] );
free( vpp->dir_cache );
free( vpp->FAT_cache );
g_num_of_fs_client--;
if ( !g_num_of_fs_client )
free( g_fs_scratch_buffer_ptr );
// free( vpp );
return ( no_error );
}
/*
==============================================================================
==============================================================================
==== Public function for file system access
==== utility
==============================================================================
==============================================================================
*/
unsigned short fs_data_copy( unsigned char *trg, unsigned char *src, unsigned short n )
{
unsigned short i;
for ( i = 0; i < n; i++ )
*trg++ = *src++;
return ( i );
}
/*
==============================================================================
==============================================================================
==== Private functions for file system access
==== accessing media
==============================================================================
==============================================================================
*/
static unsigned char make_directory_entry_fp( fs_FILE *fp )
{
return (make_directory_entry( fp->path, fp->directory_entry_cluster, &(fp->directory_entry_index), &(fp->file_info), NO_MAKE_NEW_DIR_ENT ) );
}
static unsigned char make_directory_entry( char *full_path, unsigned short parent_cluster, unsigned short *index_ptr, directory_entry *dir_ptr, unsigned char make_dir )
{
directory_entry *dp;
char name[ 12 ];
unsigned char i;
volume_param *vpp;
if ( find_entry( full_path ) )
return ( ERROR_MAKE_DIR__ENTRY_EXIST );
format_file_name_directory_entry( name, full_path + 1 + last_char_position( full_path, '/' ) );
if ( NULL == (dp = find_free_directory_entry( index_ptr, parent_cluster, name )) )
return ( error );
// initialize all field
fs_data_copy( (unsigned char *)dp, name, 11 );
dp->attributes = make_dir ? 0x10 : 0x20;
for ( i = 0; i < 10; i++ )
(dp->reserved)[ i ] = 0;
set_time_for_directory_entry( dp );
dp->cluster = 0x0000;
dp->size = 0;
// copy to file parameter structure
if ( dir_ptr )
fs_data_copy( (unsigned char *)dir_ptr, (unsigned char *)dp, sizeof( directory_entry ) );
write_back_directory_entry();
return ( no_error );
}
#if BIG_ENDIAN
static unsigned char update_directory_entry( fs_FILE *fp )
{
directory_entry *dp;
directory_entry tmp_d;
fs_data_copy( (unsigned char *)(&tmp_d), (unsigned char *)(&(fp->file_info)), sizeof( directory_entry ) );
tmp_d.time = swap16( tmp_d.time );
tmp_d.date = swap16( tmp_d.date );
tmp_d.cluster = swap16( tmp_d.cluster );
tmp_d.size = swap32( tmp_d.size );
if ( NULL == (dp = get_directory_entry( fp->directory_entry_cluster, fp->directory_entry_index, NO_MAKE_NEW_DIR_ENT )) )
return ( error );
fs_data_copy( (unsigned char *)dp, (unsigned char *)(&tmp_d), sizeof( directory_entry ) );
write_back_directory_entry();
return ( no_error );
}
#else
static unsigned char update_directory_entry( fs_FILE *fp )
{
directory_entry *dp;
if ( NULL == (dp = get_directory_entry( fp->directory_entry_cluster, fp->directory_entry_index, NO_MAKE_NEW_DIR_ENT )) )
return ( error );
fs_data_copy( (unsigned char *)dp, (unsigned char *)(&(fp->file_info)), sizeof( directory_entry ) );
write_back_directory_entry();
return ( no_error );
}
#endif
static unsigned char remove_this_entry( unsigned short base_cluster, unsigned short index, unsigned char flags, unsigned char *ep, unsigned short depth )
{
directory_entry *dp;
unsigned short sub_base;
unsigned char c;
unsigned short i;
if ( NULL == (dp = get_directory_entry( base_cluster, index, NO_MAKE_NEW_DIR_ENT )) )
return ( True );
c = *((unsigned char *)dp);
if ( c == 0 )
return ( True );
if ( dp->attributes == 0x0F )
c = 0xE5;
if ( depth && !(flags & (FLAG_REMOVE_RECURSIVE | FLAG_LEAVE_CURR_DIR)) && (c != 0xE5) )
{
*ep = FS_RM_SUB_DIRECTORY_IS_NOTEMPTY;
return ( True );
}
if ( dp->attributes & 0x10 )
{
#if BIG_ENDIAN
sub_base = swap16( dp->cluster );
#else
sub_base = dp->cluster;
#endif
if ( !depth || (flags & FLAG_REMOVE_RECURSIVE) || (c == 0xE5) )
{
i = (sub_base == ROOT_DIRECTORY_CLUSTER) ? 0 : 2;
while ( !remove_this_entry( sub_base, i++, flags, ep, depth + 1 ) )
;
}
else
{
*ep = FS_RM_SUB_DIRECTORY_EXIST;
return ( True );
}
}
dp = get_directory_entry( base_cluster, index, NO_MAKE_NEW_DIR_ENT );
if ( *ep )
return ( *ep );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -