⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs.c

📁 使用ISP1362芯片的USB_OTG参考设计源代码比较新的版本
💻 C
📖 第 1 页 / 共 5 页
字号:
	//		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 + -