/*
* file.c
*
* Created on: 21/07/2011
* Author: lyl
*/
#include "global.h"
#include "fat.h"
#include "file.h"
//-----------------------------------------------------------------------------
// Locals
//-----------------------------------------------------------------------------
static FL_FILE _files[FATFS_MAX_OPEN_FILES];
static int _filelib_init = 0;
static int _filelib_valid = 0;
static FL_FILE* _open_file_list = NULL;
static FL_FILE* _free_file_list = NULL;
static FL_FILE* _open_file(const char *path);
static void _free_file(FL_FILE* file);
void fl_init(void)
{
int i;
// Add all file objects to free list
for (i=0;i<FATFS_MAX_OPEN_FILES;i++)
{
_files[i].next = _free_file_list;
_free_file_list = &_files[i];
}
_filelib_init = 1;
}
int fl_list_opendir(const char *path, FAT_DIR_STATUS *dirls)
{
int levels;
UINT32 cluster = FAT32_INVALID_CLUSTER;
// If first call to library, initialise
CHECK_FL_INIT();
// If path is in the root dir
cluster =0;// fatfs_get_root_cluster();
fatfs_list_directory_start(dirls, cluster);
return cluster != FAT32_INVALID_CLUSTER ? 1 : 0;
}
int fl_list_readdir(FAT_DIR_STATUS *dirls, FAT_DIR_ENTRY *entry)
{
int res = 0;
// If first call to library, initialise
CHECK_FL_INIT();
res = fatfs_list_directory_next(dirls, entry);
return res;
}
//-----------------------------------------------------------------------------
// _read_sector: Read a sector from disk to file
//-----------------------------------------------------------------------------
static int _read_sector(FL_FILE* file, UINT32 offset)
{
UINT32 Sector = 0;
UINT32 ClusterIdx = 0;
UINT32 Cluster = 0;
UINT32 i;
UINT32 lba;
FAT_SYSTEM * _fs;
_fs=get_current_fat_system();
// Find cluster index within file & sector with cluster
ClusterIdx = offset / _fs->sectors_per_cluster;
Sector = offset - (ClusterIdx * _fs->sectors_per_cluster);
// Quick lookup for next link in the chain
if (ClusterIdx == file->last_fat_lookup.ClusterIdx)
Cluster = file->last_fat_lookup.CurrentCluster;
// Else walk the chain
else
{
// Starting from last recorded cluster?
if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1)
{
i = file->last_fat_lookup.ClusterIdx;
Cluster = file->last_fat_lookup.CurrentCluster;
}
// Start searching from the beginning..
else
{
// Set start of cluster chain to initial value
i = 0;
Cluster = file->startcluster;
}
// Follow chain to find cluster to read
for ( ;i<ClusterIdx; i++)
{
UINT32 nextCluster;
// Does the entry exist in the cache?
if (!fatfs_cache_get_next_cluster(&_fs, file, i, &nextCluster))
{
// Scan file linked list to find next entry
nextCluster = fatfs_find_next_cluster(&_fs, Cluster);
// Push entry into cache
fatfs_cache_set_next_cluster(&_fs, file, i, nextCluster);
}
Cluster = nextCluster;
}
// Record current cluster lookup details (if valid)
if (Cluster != FAT32_LAST_CLUSTER)
{
file->last_fat_lookup.CurrentCluster = Cluster;
file->last_fat_lookup.ClusterIdx = ClusterIdx;
}
}
// If end of cluster chain then return false
if (Cluster == FAT32_LAST_CLUSTER)
return 0;
// Calculate sector address
lba = fatfs_lba_of_cluster(&_fs, Cluster) + Sector;
char debug[20];
FAT_SYSTEM *fs;
fs=get_current_fat_system();
DWORD size;
size= fs->rootdir_sectors;
sprintf(debug,"LBA:%d SEC:%d\r\n",lba,size);
LW_ASSERT(TRUE,debug);
// Read sector of file
return fatfs_sector_reader(lba, size,NULL);
}
FAT_DIR_STATUS dirstat;
FAT_DIR_ENTRY dirent;
void fl_listdirectory(const char *path)
{
int filenumber = 0;
char debug[50];
// If first call to library, initialise
CHECK_FL_INIT();
LW_ASSERT(TRUE,"\r\nNo. Filename\r\n");
if (fl_list_opendir(path, &dirstat))
{
//fl_list_readdir(&dirstat, &dirent);
while (fl_list_readdir(&dirstat, &dirent))
{
if (dirent.is_dir)
{
sprintf(debug,"%d - %s <DIR> (0x%08lx)\r\n",++filenumber, dirent.filename, dirent.cluster);
LW_ASSERT(TRUE,debug);
}
else
{
sprintf(debug,"%d - %s [%d bytes] (0x%08lx)\r\n",++filenumber, dirent.filename, dirent.size, dirent.cluster);
LW_ASSERT(TRUE,debug);
strcpy(debug,path);
FL_FILE* file=_open_file(strcat(debug,dirent.filename));
fl_fread(debug,file->filelength,file);
LW_ASSERT(TRUE,debug);
_free_file(file);
}
}
}
LW_ASSERT(TRUE,"\r\nEND OF FILE LIST\r\n");
}
//-----------------------------------------------------------------------------
// _open_directory: Cycle through path string to find the start cluster
// address of the highest subdir.
//-----------------------------------------------------------------------------
static int _open_directory(char *path, unsigned long *pathCluster)
{
int levels;
int sublevel;
char currentfolder[FATFS_MAX_LONG_FILENAME];
FAT_FILE_ENTRY sfEntry;
unsigned long startcluster;
FAT_SYSTEM * fs;
fs=get_current_fat_system();
// Set starting cluster to root cluster
startcluster = fatfs_get_root_cluster(fs);
// Find number of levels
levels = fatfs_total_path_levels(path);
// Cycle through each level and get the start sector
for (sublevel=0;sublevel<(levels+1);sublevel++)
{
if (fatfs_get_substring(path, sublevel, currentfolder, sizeof(currentfolder)) == -1)
return 0;
// Find clusteraddress for folder (currentfolder)
if (fatfs_get_file_entry(fs, startcluster, currentfolder,&sfEntry))
{
// Check entry is folder
if (fatfs_entry_is_dir(&sfEntry))
startcluster = (((unsigned long)sfEntry.FstClusHI)<<16) + sfEntry.FstClusLO;
else
return 0;
}
else
return 0;
}
*pathCluster = startcluster;
return 1;
}
//-----------------------------------------------------------------------------
// _check_file_open: Returns true if the file is already open
//-----------------------------------------------------------------------------
static int _check_file_open(FL_FILE* file)
{
FL_FILE* openFile = _open_file_list;
// Compare open files
while (openFile)
{
// If not the current file
if (openFile != file)
{
// Compare path and name
//if ( (fatfs_compare_names(openFile->path,file->path)) && (fatfs_compare_names(openFile->filename,file->filename)) )
// return 1;
}
openFile = openFile->next;
}
return 0;
}
//-----------------------------------------------------------------------------
// fl_fread: Read a block of data from the file
//-----------------------------------------------------------------------------
int fl_fread(void * buffer, int length, void *f )
{
unsigned long sector;
unsigned long offset;
int copyCount;
int bytesRead = 0;
int count;
count=length;
FL_FILE *file = (FL_FILE *)f;
// If first call to library, initialise
CHECK_FL_INIT();
if (buffer==NULL || file==NULL)
return -1;
// No read permissions
//if (!(file->flags & FILE_READ))
// return -1;
// Nothing to be done
//if (!count)
// return 0;
// Check if read starts past end of file
//if (file->bytenum >= file->filelength)
// return -1;
// Calculate start sector
sector = file->bytenum / FAT_SECTOR_SIZE;
// Offset to start copying data from first sector
offset = file->bytenum % FAT_SECTOR_SIZE;
while (bytesRead < length)
{
// Do we need to re-read the sector?
if (file->file_data.address != sector)
{
// Flush un-written data to file
//if (file->file_data.dirty)
// fl_fflush(file);
// Get LBA of sector offset within file
if (!_read_sector(file, sector))
// Read failed - out of range (probably)
break;
file->file_data.address = sector;
file->file_data.dirty = 0;
}
// We have upto one sector to copy
copyCount = FAT_SECTOR_SIZE - offset;
// Only require some of this sector?
if (copyCount > (count - bytesRead))
copyCount = (count - bytesRead);
// Copy to application buffer
memcpy( (unsigned char*)((unsigned char*)buffer + bytesRead), (unsigned char*)(file->file_data.sector + offset), copyCount);
// Increase total read count
bytesRead += copyCount;
// Increment file pointer
file->bytenum += copyCount;
// Move onto next sector and reset copy offset
sector++;
offset = 0;
}
return bytesRead;
}
//-----------------------------------------------------------------------------
// _allocate_file: Find a slot in the open files buffer for a new file
//-----------------------------------------------------------------------------
static FL_FILE* _allocate_file(void)
{
// Allocate free file
FL_FILE* file = _free_file_list;
if (file)
{
_free_file_list = file->next;
// Add to open list
file->next = _open_file_list;
_open_file_list = file;
}
return file;
}
//-----------------------------------------------------------------------------
// _free_file: Free open file handle
//-----------------------------------------------------------------------------
static void _free_file(FL_FILE* file)
{
FL_FILE* openFile = _open_file_list;
FL_FILE* lastFile = NULL;
// Remove from open list
while (openFile)
{
// If the current file
if (openFile == file)
{
if (lastFile)
lastFile->next = openFile->next;
else
_open_file_list = openFile->next;
break;
}
lastFile = openFile;
openFile = openFile->next;
}
// Add to free list
file->next = _free_file_list;
_free_file_list = file;
}
//-----------------------------------------------------------------------------
// _open_file: Open a file for reading
//-----------------------------------------------------------------------------
static FL_FILE* _open_file(const char *path)
{
FL_FILE* file;
//#define struct fat_dir_entry FAT_FILE_ENTRY
FAT_FILE_ENTRY sfEntry;
// Allocate a new file handle
file = _allocate_file();
if (!file)
return NULL;
// Clear filename
memset(file->path, '\0', sizeof(file->path));
memset(file->filename, '\0', sizeof(file->filename));
// Split full path into filename and directory path
if (fatfs_split_path((char*)path, file->path, sizeof(file->path), file->filename, sizeof(file->filename)) == -1)
{
_free_file(file);
return NULL;
}
char debug[50];
sprintf(debug,"Parsed File Name:%s\r\n",file->filename);
LW_ASSERT(TRUE,debug);
// Check if file already open
if (_check_file_open(file))
{
_free_file(file);
return NULL;
}
// If file is in the root dir
if (file->path[0]==0)
file->parentcluster = fatfs_get_root_cluster();
else
{
// Find parent directory start cluster
if (!_open_directory(file->path, &file->parentcluster))
{
_free_file(file);
return NULL;
}
}
LW_ASSERT(TRUE,"About to Open file\r\n");
// Using dir cluster address search for filename
if (fatfs_get_file_entry(get_current_fat_system(), file->parentcluster, file->filename,&sfEntry))
{ // Make sure entry is file not dir!
// Initialise file details
memcpy(file->shortfilename, sfEntry.Name, FAT_SFN_SIZE_FULL);
file->filelength = fat_get_file_size(&sfEntry);
file->bytenum = 0;
file->startcluster =fat_get_file_cluster(&sfEntry);
char debug[20];
sprintf(debug,"File Cluster:%d\r\n",file->startcluster);
LW_ASSERT(TRUE,debug);
file->file_data.address = 0xFFFFFFFF;
file->file_data.dirty = 0;
file->filelength_changed = 0;
// Quick lookup for next link in the chain
file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
return file;
}
_free_file(file);
return NULL;
}