📄 fs.c
字号:
/*
** WASABI-Hot! version 1.2c
**
**
** -- copyright (c) 2001-2004 by Philips Japan, Ltd. -- All rights reserved --
**
**
** ** This code has been made to check/learn **
** ** the ISP1362/ISP1363 functionalities **
** ** Release 06-Aug-2004 **
**
** OKANO, Akifumi
**
** Application Laboratory, Mobile and Connectivity
** Semiconductors Div, Philips Japan Ltd.
** akifumi.okano@philips.com
** +81-3-3740-4668
*/
/****************************************************************************/
/* includes */
/****************************************************************************/
#include <alloc.h>
#include "class_dr/storage/storage.h"
#include "class_dr/storage/fs.h"
#include "ui.h"
#include "general.h"
/****************************************************************************/
/* constants */
/****************************************************************************/
// directory accessing mode
#define DIR_ACCESS_READ 0
#define DIR_ACCESS_MODIFY 1
#define DIR_ACCESS_APPEND_NEW 2
#define DIR_ACCESS_APPEND_OW 3
#define FAT_CACHE_NOT_VALID 0xFFFFFFFF
#define DIR_CACHE_NOT_VALID 0xFFFFFFFF
#define NO_DIR_MODIFY 0
#define OK_DIR_MODIFY 1
#define NO_MAKE_NEW_DIR_ENT 0
#define OK_MAKE_NEW_DIR_ENT 1
#define FILE_SYSTEM_FAT16 0
#define FILE_SYSTEM_FAT12 1
#define FILE_SYSTEM_UNKNOWN 0xFF
/****************************************************************************/
/* global vars */
/****************************************************************************/
drive_param gp_drive_parameter;
volume_param g_volume_parameter;
unsigned char *g_fs_scratch_buffer_ptr;
unsigned short g_fs_scratch_buffer_size;
unsigned char g_num_of_fs_client = 0;
unsigned char g_recent_error;
#if BIG_ENDIAN
directory_entry g_root_dumy = { "ROOTROOT", "DIR", 0x10, {0,0,0,0,0,0,0,0,0,0}, 0, 0,
// ROOT_DIRECTORY_CLUSTER,
(ROOT_DIRECTORY_CLUSTER << 8) | (ROOT_DIRECTORY_CLUSTER >> 8),
0 };
#else
directory_entry g_root_dumy = { "ROOTROOT", "DIR", 0x10, {0,0,0,0,0,0,0,0,0,0}, 0, 0, ROOT_DIRECTORY_CLUSTER, 0 };
#endif
/****************************************************************************/
/* function prototypes */
/****************************************************************************/
static unsigned short fs_read_large( fs_FILE *fp, unsigned char *buffer_ptr, unsigned long clusters );
static unsigned short fs_read_small( fs_FILE *fp, unsigned char *buffer_ptr, unsigned short length );
static unsigned short fs_write_large( fs_FILE *fp, unsigned char *buffer_ptr, unsigned long clusters );
static unsigned short fs_write_small( fs_FILE *fp, unsigned char *buffer_ptr, unsigned short length );
static unsigned char make_directory_entry_fp( fs_FILE *fp );
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 );
static unsigned char update_directory_entry( fs_FILE *fp );
static unsigned char remove_this_entry( unsigned short base_cluster, unsigned short index, unsigned char flags, unsigned char *ep, unsigned short depth );
static unsigned short count_free_cluster( void );
static unsigned short find_free_cluster( unsigned short start_cluster );
static unsigned char clear_FAT_chain( unsigned short cluster );
static unsigned char valid_cluster( unsigned short cluster, volume_param *vpp );
static unsigned short read_FAT( unsigned short current_cluster );
static unsigned short write_FAT( unsigned short cluster, unsigned short value );
static unsigned short flush_FAT_cache( volume_param *vpp );
static unsigned short flush_FAT16_cache( volume_param *vpp );
static unsigned short flush_FAT12_cache( volume_param *vpp );
static unsigned short access_FAT16( unsigned char mode, unsigned short cluster, unsigned short value );
static unsigned short access_FAT12( unsigned char mode, unsigned short cluster, unsigned short value );
static unsigned long cluster_to_sector( unsigned short cluster );
static directory_entry *find_entry( char *path );
static directory_entry *find_file_entry( char *path, unsigned short *dir_cluster_ptr, unsigned short *index_ptr );
static directory_entry *find_directory_index( unsigned short *found_index, unsigned short base_cluster, char *name );
static directory_entry *find_free_directory_entry( unsigned short *found_index, unsigned short base_cluster, char *name );
static directory_entry *get_directory_entry( unsigned short base_cluster, unsigned short index, unsigned char new_entry_ok );
static void write_back_directory_entry( void );
static void set_time_for_directory_entry( directory_entry *d );
static unsigned char format_file_name_directory_entry( char *target_base, char *source );
static unsigned char str_match( char *a, char *b, unsigned char n );
static void make_full_path( char *target, char *relative, char *current );
static char *reform_path( char *source );
static void separate_directory_and_file( char *directory_path, char *file_name, char *source );
static unsigned short first_char_position( char *path, char mc );
static unsigned short last_char_position( char *path, char mc );
/****************************************************************************/
/* function definitions */
/****************************************************************************/
/*
==============================================================================
==============================================================================
==== Public functions for file system access
==== Functions for APPLICATION side
==============================================================================
==============================================================================
*/
//////////
////////// "cd" change directory
//////////
unsigned char fs_cd( char *path )
{
char full_path[ MAX_PATH_STRING_LENGTH ];
directory_entry *dp;
volume_param *vpp;
vpp = &g_volume_parameter;
if ( NULL == (dp = find_entry( path )) )
return ( error );
if ( !(dp->attributes & 0x10) )
return ( error );
make_full_path( full_path, path, vpp->current_dir );
#if BIG_ENDIAN
vpp->current_directory_cluster = swap16( dp->cluster );
#else
vpp->current_directory_cluster = dp->cluster;
#endif
fs_data_copy( (unsigned char *)(vpp->current_dir), (unsigned char *)full_path, MAX_PATH_STRING_LENGTH );
return ( no_error );
}
//////////
////////// "pwd" working directory name
//////////
void fs_pwd( char *pwd_str )
{
volume_param *vpp;
vpp = &g_volume_parameter;
fs_data_copy( (unsigned char *)pwd_str, (unsigned char *)(vpp->current_dir), MAX_PATH_STRING_LENGTH );
}
//////////
////////// "ls" get list
//////////
unsigned char fs_ls( char *path, directory_entry *dir, unsigned short entries )
{
fs_FILE *fp;
char full_path[ MAX_PATH_STRING_LENGTH ];
unsigned char *buffer_ptr_base;
unsigned char *buffer_ptr;
volume_param *vpp;
unsigned short i;
unsigned short count = 0;
vpp = &g_volume_parameter;
make_full_path( full_path, path, vpp->current_dir );
if ( str_match( full_path, "/", 2 ) )
{
// root directory
entries = (vpp->root_directory_entries < entries) ? vpp->root_directory_entries : entries;
buffer_ptr_base = g_fs_scratch_buffer_ptr;
for ( i = 0; i < entries; i++ )
{
if ( !( i % ((vpp->bytes_per_cluster) / sizeof( directory_entry )) ) )
{
storage_read_sector( buffer_ptr_base, vpp->start_sector_root_directory + count++, vpp->sector_per_cluster );
buffer_ptr = buffer_ptr_base;
}
*dir++ = *((directory_entry *)buffer_ptr)++;
}
}
else
{
unsigned short l_read;
unsigned short n_read;
if ( NULL == (fp = fs_fopen( full_path, R | D )) )
{
return ( error );
}
l_read = sizeof( directory_entry ) * entries;
if ( l_read != (n_read = fs_read( fp, (unsigned char *)dir, l_read )) )
*((unsigned char *)dir + n_read) = 0;
fs_fclose( fp );
}
return ( no_error );
}
//////////
////////// "fopen" file open
//////////
fs_FILE *fs_fopen( char *path, unsigned char mode )
{
fs_FILE *fp;
directory_entry *dp;
volume_param *vpp;
unsigned char index;
vpp = &g_volume_parameter;
// to find open slot to register this open-file
for ( index = 0; index < MAX_OPEN_FILES; index++ )
if ( (vpp->opened_FILE_pointer)[ index ] == NULL )
break;
if ( index == MAX_OPEN_FILES )
{
//mprintf( WHITE, CONTINUE, "\r\nerror @ fs_fopen : MAX_OPEN_FILES\r\n" );
g_recent_error = 2;
return ( NULL );
}
// allocate fs_FILE structure
if ( NULL == ( fp = (fs_FILE *)malloc( sizeof( fs_FILE ) ) ) )
{
//mprintf( WHITE, CONTINUE, "\r\nerror @ fs_fopen : malloc1\r\n" );
g_recent_error = 3;
return ( NULL );
}
// allocate file buffer (this works as a cache for the disk)
if ( NULL == ( fp->cluster_buffer_pointer = (unsigned char *)malloc( vpp->bytes_per_cluster ) ) )
{
//mprintf( WHITE, CONTINUE, "\r\nerror @ fs_fopen : malloc2\r\n" );
g_recent_error = 4;
free( fp );
return ( NULL );
}
make_full_path( fp->path, path, vpp->current_dir );
separate_directory_and_file( fp->path_to_dir, fp->file_name, fp->path );
if ((mode & 0x01) == FS_WRITE)
{
// if opening for "write", needed to be sure the parent directory exists
if ( NULL == find_entry( fp->path_to_dir ) )
{
// no parent directory
//mprintf( WHITE, CONTINUE, "\r\nerror @ fs_fopen : no parent directory\r\n" );
g_recent_error = 9;
free( fp->cluster_buffer_pointer );
free( fp );
return ( NULL );
}
}
dp = find_file_entry( path, &(fp->directory_entry_cluster), &(fp->directory_entry_index) );
if ( (dp->attributes & 0x10) && ((mode & 0x01) != FS_WRITE) )
{
if ( (mode & 0x08) != FS_OPN_DIR )
{
//mprintf( WHITE, CONTINUE, "\r\nerror @ fs_fopen : FS_OPN_DIR\r\n" );
g_recent_error = 10;
free( fp );
return ( NULL );
}
}
if ( dp )
{
fs_data_copy( (unsigned char *)(&(fp->file_info)), (unsigned char *)dp, sizeof( directory_entry ) );
#if BIG_ENDIAN
(fp->file_info).time = swap16( (fp->file_info).time );
(fp->file_info).date = swap16( (fp->file_info).date );
(fp->file_info).cluster = swap16( (fp->file_info).cluster );
(fp->file_info).size = swap32( (fp->file_info).size );
#endif
fp->start_cluster = (fp->file_info).cluster;
}
else
{
fp->start_cluster = 0;
}
fp->current_cluster = 0;
fp->buffered_cluster = 0;
fp->number_of_cluster_processed = 0;
fp->current_file_data_position = 0;
fp->volume_param_ptr = vpp;
fp->index = index;
fp->mode = mode;
(vpp->opened_FILE_pointer)[ index ] = fp;
if ((mode & 0x01) == FS_READ)
{
// to open a file to READ
if ( !(fp->start_cluster) )
{
//mprintf( WHITE, CONTINUE, "\r\nerror @ fs_fopen : FS_READ\r\n" );
g_recent_error = 5;
free( fp );
return ( NULL );
}
}
else if ((mode & 0x01) == FS_WRITE)
{
// to open a file to WRITE
if ( (fp->start_cluster) )
{
if ((mode & 0x02) == FS_PROTECT)
{
// for when the over write PROTECTed
//mprintf( WHITE, CONTINUE, "\r\nerror @ fs_fopen : FS_PROTECT\r\n" );
g_recent_error = 5;
free( fp );
return ( NULL );
}
else
{
// for OVERWRITE an existing file
fs_rm( fp->path, False );
}
}
// make directry entry for the file
make_directory_entry_fp( fp );
// find an open cluster to write file data
fp->start_cluster = find_free_cluster( 2 ); // find open cluster
write_FAT( fp->start_cluster, 0xFFFF );
flush_FILE_write_buffer( fp );
}
return ( fp );
}
//////////
////////// "fclose" file close
//////////
void fs_fclose( fs_FILE *fp )
{
if ( !storage_volume_ready() )
return;
if ( fp == NULL )
return;
if ( fp->mode != FS_READ )
{
flush_FILE_write_buffer( fp );
flush_FAT_cache( (volume_param *)(fp->volume_param_ptr) );
update_directory_entry( fp );
}
(((volume_param *)(fp->volume_param_ptr))->opened_FILE_pointer)[ fp->index ] = NULL;
free( fp->cluster_buffer_pointer );
free( fp );
}
//////////
////////// "read" file read
//////////
unsigned short fs_read( fs_FILE *fp, unsigned char *buffer_ptr, unsigned short length )
{
unsigned short size_of_pre_read;
unsigned short num_of_large_read_clusters;
unsigned short size_of_post_read;
unsigned short data_offset_in_cluster;
unsigned short read_clusters;
unsigned short size;
unsigned short size_of_total_read = 0;
unsigned long remaining_file_size;
volume_param *vpp;
vpp = fp->volume_param_ptr;
// calcurate file data size left
if ( (fp->file_info).attributes & 0x10 )
remaining_file_size = vpp->bytes_per_cluster; // Possible problem : No bigger directory handling
else
remaining_file_size = (fp->file_info).size - fp->current_file_data_position;
// limit file reading size to file size.
// to prevent over reading.
length = ((unsigned long)length < remaining_file_size) ? length : (unsigned short)remaining_file_size;
if ( length < vpp->bytes_per_cluster )
{
size_of_pre_read = length;
num_of_large_read_clusters = 0;
size_of_post_read = 0;
}
else
{
data_offset_in_cluster = fp->current_file_data_position % vpp->bytes_per_cluster;
size_of_pre_read = data_offset_in_cluster ? (vpp->bytes_per_cluster - data_offset_in_cluster) : 0;
length -= size_of_pre_read;
if ( length < vpp->bytes_per_cluster )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -