54,7 → 54,7 |
// + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// + POSSIBILITY OF SUCH DAMAGE. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
//#include <stdio.h> |
#include <stdio.h> |
#include "91x_lib.h" |
#include "fat16.h" |
#include "sdc.h" |
230,9 → 230,9 |
|
#define SLOT_EMPTY 0x00 // slot has never been used |
#define SLOT_E5 0x05 // the real value is 0xe5 |
#define SLOT_DELETED 0xe5 // file in this slot deleted |
#define SLOT_DELETED 0xE5 // file in this slot deleted |
|
#define ATTR_NORMAL 0x00 // normal file |
#define ATTR_NONE 0x00 // normal file |
#define ATTR_READONLY 0x01 // file is readonly |
#define ATTR_HIDDEN 0x02 // file is hidden |
#define ATTR_SYSTEM 0x04 // file is a system file |
289,6 → 289,7 |
u32 FirstFatSector; // sector of the start of the fat |
u32 FirstRootDirSector; // sector of the rootdirectory |
u32 FirstDataSector; // sector of the first cluster containing data (cluster2). |
u32 LastDataSector; // the last data sector of the partition |
} Partition_t; |
|
Partition_t Partition; // Structure holds partition information |
295,6 → 296,7 |
|
File_t FilePointer[FILE_MAX_OPEN]; // Allocate Memmoryspace for each filepointer used. |
|
|
/****************************************************************************************************************************************/ |
/* Function: SeperateDirName(u8*, u8*, u8*); */ |
/* */ |
302,22 → 304,23 |
/* into the needed format ('test.txt' -> 'TEST TXT') */ |
/* The subpath is the pointer to the remaining substring if the filepath */ |
/* */ |
/* Returnvalue: Return 0 on error */ |
/* Returnvalue: Return 0 on error ot pointer to subpath */ |
/****************************************************************************************************************************************/ |
u8 SeperateDirName(const u8 *filepath, u8 *dirname, u8 *subpath) |
u8* SeperateDirName(const u8 *filepath, u8 *dirname) |
{ |
u8* readpointer = 0; |
u8* subpath = 0; |
u8 readpointer = 0; |
u8 writepointer = 0; |
|
// search subpath from beginning of filepath |
subpath = 0; |
readpointer = (u8*)filepath; |
if(*readpointer == '/') readpointer++; // ignore first '/' |
readpointer = 0; |
if(filepath[0] == '/') readpointer = 1; // ignore first '/' |
while(!subpath) // search the filepath until a subpath was found. |
{ |
if(((*readpointer == 0) || (*readpointer == '/'))) // if '/' found or end of filepath reached |
if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/'))) // if '/' found or end of filepath reached |
{ |
subpath = readpointer; // store the position of the first "/" found after the beginning of the filenpath |
subpath = (u8*)&filepath[readpointer]; // store the position of the first "/" found after the beginning of the filenpath |
} |
readpointer++; |
} |
326,12 → 329,12 |
for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' '; |
writepointer = 0; |
// start seperating the dirname from the filepath. |
readpointer = (u8*)filepath; |
if(*readpointer == '/') readpointer++; // ignore first '/' |
while( readpointer < subpath) |
readpointer = 0; |
if(filepath[0] == '/') readpointer = 1; // ignore first '/' |
while( &filepath[readpointer] < subpath) |
{ |
if(writepointer >= 11) return 0; // dirname to long |
if(*readpointer == '.') // seperating dirname and extension. |
if(filepath[readpointer] == '.') // seperating dirname and extension. |
{ |
if(writepointer<8) |
{ |
342,19 → 345,19 |
} |
else |
{ |
if((0x60 < *readpointer) && (*readpointer < 0x7B)) |
if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B)) |
{ |
dirname[writepointer] = (*readpointer - 0x20); // all characters must be upper case. |
dirname[writepointer] = (filepath[readpointer] - 0x20); // all characters must be upper case. |
} |
else |
{ |
dirname[writepointer] = *readpointer; |
dirname[writepointer] = filepath[readpointer]; |
} |
readpointer++; |
writepointer++; |
} |
} |
return (1); |
return (subpath); |
} |
|
|
393,7 → 396,7 |
/* */ |
/* Returnvalue: The function returns "0" if the filesystem is initialized. */ |
/****************************************************************************************************************************************/ |
s16 InitFat16_Init(void) |
s16 Fat16_Init(void) |
{ |
u8 cnt = 0; |
u32 PartitionFirstSector; |
415,7 → 418,7 |
cnt = 0; |
while(SD_SUCCESS != SDC_Init()) |
{ |
if(cnt > 200) |
if(cnt > 5) |
{ |
SerialPutString("SD-Card could not be initialized.\r\n"); |
return(1); |
464,6 → 467,13 |
// Calculate the position of the first datacluster: |
// Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector) |
Partition.FirstDataSector = Partition.FirstRootDirSector + (u32)(Partition.MaxRootEntries>>4); // assuming 512 Byte Per Sector |
// Calculate the last data sector |
if(VBR->NoSectors == 0) |
{ |
SerialPutString("Bad nuber of sectors in this partition.\r\n"); |
return(4); |
} |
Partition.LastDataSector = Partition.FirstDataSector + VBR->NoSectors - 1; |
// check for FAT16 in VBR of first partition |
if(!((VBR->FATName[0]=='F') && (VBR->FATName[1]=='A') && (VBR->FATName[2]=='T') && (VBR->FATName[3]=='1')&&(VBR->FATName[4]=='6'))) |
{ |
499,10 → 509,26 |
return(returnvalue); |
} |
|
/****************************************************************************************************************************************/ |
/* Function: ClearCurrCluster(File_t file); */ |
/* */ |
/* Description: This function fills the current cluster with 0. */ |
/* */ |
/* Returnvalue: The function returns 1 on success else 0. */ |
/****************************************************************************************************************************************/ |
u8 ClearCurrCluster(File_t * File) |
{ |
u8 retvalue = 1; |
u32 i; |
for(i = 0; i < BYTES_PER_SECTOR; i++) File->Cache[i] = 0; // clear file cache |
for(i = 0; i < Partition.SectorsPerCluster; i++) |
{ |
File->SectorInCache = File->FirstSectorOfCurrCluster + i; |
if(SD_SUCCESS != SDC_PutSector(File->SectorInCache, File->Cache)) retvalue = 0; |
} |
return(retvalue); |
} |
|
|
|
|
/*****************************************************************************************************************************************/ |
/* Function: GetNextCluster(File_t file); */ |
/* */ |
518,7 → 544,7 |
|
if(File == 0) return(cluster); |
// if sector is within the data area |
if(Partition.FirstDataSector <= File->FirstSectorOfCurrCluster) |
if((Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)&& (File->FirstSectorOfCurrCluster <= Partition.LastDataSector)) |
{ |
// determine current file cluster |
cluster = SectorToFat16Cluster(File->FirstSectorOfCurrCluster); |
549,21 → 575,6 |
File->ByteOfCurrSector = 0; |
} |
} |
// if sector is within the root directory |
else if((Partition.FirstRootDirSector <= File->FirstSectorOfCurrCluster) && (File->FirstSectorOfCurrCluster < Partition.FirstDataSector)) |
{ |
if((File->FirstSectorOfCurrCluster + 1) == Partition.FirstDataSector) |
{ |
cluster = 0; |
} |
else |
{ |
File->FirstSectorOfCurrCluster++; |
File->SectorOfCurrCluster = 0; |
File->ByteOfCurrSector = 0; |
cluster = 1; |
} |
} |
return(cluster); |
} |
|
591,7 → 602,11 |
{ |
curr_sector = Partition.FirstFatSector + fat_sector; // calculate sector to read |
File->SectorInCache = curr_sector; // upate the sector number of file cache. |
SDC_GetSector(File->SectorInCache, File->Cache); // read sector of fat from sd-card. |
if( SD_SUCCESS != SDC_GetSector(File->SectorInCache, File->Cache)) // read sector of fat from sd-card. |
{ |
return(free_cluster); |
} |
|
Fat = (Fat16Entry_t *)File->Cache; // set fat pointer to file cache |
|
for(fat_entry = 0; fat_entry < FAT16_ENTRIES_PER_SECTOR; fat_entry++) // look for an free cluster at all entries in this sector of the fat. |
599,8 → 614,10 |
if(Fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE) // empty cluster found!! |
{ |
Fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX; // mark this fat-entry as used |
SDC_PutSector(File->SectorInCache, File->Cache); // and save the sector at the sd-card. |
|
if(SD_SUCCESS != SDC_PutSector(File->SectorInCache, File->Cache)) // and save the sector at the sd-card. |
{ |
return(free_cluster); |
} |
free_cluster = (u16)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (u32)fat_entry); |
fat_entry = FAT16_ENTRIES_PER_SECTOR; // terminate the search for a free cluster in this sector. |
} |
715,18 → 732,19 |
File->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster); |
File->SectorOfCurrCluster = 0; |
File->ByteOfCurrSector = 0; |
ClearCurrCluster(File); |
} |
return(new_cluster); |
} |
|
/****************************************************************************************************************************************************/ |
/* Function: DirectoryEntryExist(u8 *, File_t *) */ |
/* Function: DirectoryEntryExist(u8 *, u8, u8, File_t *) */ |
/* */ |
/* Description: This function searches all possible dir entries until the file or directory is found or the end of thedirectory is reached */ |
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached */ |
/* */ |
/* Returnvalue: This function returns 1 if the directory entry specified was found. */ |
/****************************************************************************************************************************************************/ |
u8 DirectoryEntryExist(u8 *dirname, File_t *File) |
u8 DirectoryEntryExist(u8 *dirname, u8 attribfilter, u8 attribmask, File_t *File) |
{ |
u32 dir_sector, max_dir_sector, curr_sector; |
u16 dir_entry = 0; |
733,33 → 751,65 |
|
u16 end_of_directory_not_reached = 0; |
u8 i = 0; |
u8 retvalue = 0; |
u8 direntry_exist = 0; |
DirEntry_t * Dir; |
|
if(File == 0) return(0); |
// if incomming pointers are useless return immediatly |
if((File == 0) || (dirname == 0)) return(direntry_exist); |
|
// dir entries can be searched only in filesclusters that have |
// the dir-flag set in its attribute or within the root directory |
|
// within the root directory area its allways valid to search a directory entry |
if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector)) |
// a corresponding dir entry with adir-flag set in its attribute |
// or direct within the root directory area |
|
File->FirstSectorOfFirstCluster = 0; |
// no current directory exist therefore assume searching in the root |
if(File->DirectorySector == 0) |
{ |
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR; |
File->FirstSectorOfFirstCluster = Partition.FirstRootDirSector; |
} |
// within the root directory area we can read sectors sequentially until the end of this area |
else if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector)) |
{ |
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR; |
} |
// check if directory entry of current file has the dir-flag set |
else if(Partition.FirstDataSector <= File->DirectorySector) |
// within the data clusters we can read sectors sequentially only within the cluster |
else if((Partition.FirstDataSector <= File->DirectorySector) && (File->DirectorySector <= Partition.LastDataSector)) |
{ |
max_dir_sector = Partition.SectorsPerCluster; |
File->SectorInCache = File->DirectorySector; // upate the sector number of file cache. |
max_dir_sector = Partition.SectorsPerCluster; // limit max secters before next cluster |
} |
else return (direntry_exist); // bad sector range for directory sector of the file |
// if search area is not defined yet |
if(File->FirstSectorOfFirstCluster == 0) |
{ |
// check if the directory entry of current file is existent and has the dir-flag set |
File->SectorInCache = File->DirectorySector; // update the sector number of file cache. |
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector. |
Dir = (DirEntry_t *)File->Cache; // set pointer to directory |
if(Dir[File->DirectoryIndex].Attribute != ATTR_SUBDIRECTORY) |
{ // current file is not a directory |
return (0); |
switch(Dir[File->DirectoryIndex].Name[0]) // check if current directory exist |
{ |
case SLOT_EMPTY: |
case SLOT_DELETED: |
// the directrory pointer of this file points to a deleted or not existen directory |
// therefore no file or subdirectory can be created |
return (direntry_exist); |
break; |
default: // and is a real directory |
if((Dir[File->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY) |
{ // current file is not a directory therefore no file or subdirectory can be created here |
return (direntry_exist); |
} |
break; |
} |
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(Dir[File->DirectoryIndex].StartCluster); |
} |
else return (0); // bad sector range for directory sector of the file |
|
do // loop over all clusters of the curernt directory |
// update current file data area position to start of first cluster |
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster; |
File->SectorOfCurrCluster = 0; |
File->ByteOfCurrSector = 0; |
|
do // loop over all data clusters of the current directory entry |
{ |
dir_sector = 0; // reset sector counter within a new cluster |
do // loop over all sectors of a cluster or all sectors of the root directory |
766,11 → 816,11 |
{ |
curr_sector = File->FirstSectorOfCurrCluster + dir_sector; // calculate sector number |
File->SectorInCache = curr_sector; // upate the sector number of file cache. |
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector. |
SDC_GetSector(File->SectorInCache, File->Cache); // read the sector |
Dir = (DirEntry_t *)File->Cache; // set pointer to directory |
// search all directory entries of a sector |
// search all directory entries within that sector |
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++) |
{ |
{ // check for existing dir entry |
switch(Dir[dir_entry].Name[0]) |
{ |
case SLOT_EMPTY: |
778,33 → 828,36 |
// ignore empty or deleted dir entries |
break; |
default: |
// check attributes before names are compared will safe performance |
if (Dir[dir_entry].Attribute != File->Attribute) break; // attribute must match |
// compare the dirname to filename (first 9 characters including 8 char of the dirname and padded space char.) |
// if existing check attributes before names are compared will safe performance |
if ((Dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match |
// then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.) |
i = 0; |
while((i < 11) && (Dir[dir_entry].Name[i] == dirname[i])) i++; |
if (i < 10) break; // names does not match |
File->Attribute = Dir[dir_entry].Attribute; // store attribute of dir entry |
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(Dir[dir_entry].StartCluster); // set start cluster sector |
// if dirname and attribute have matched |
File->Attribute = Dir[dir_entry].Attribute; // store attribute of found dir entry |
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(Dir[dir_entry].StartCluster); // set sector of first data cluster |
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster; |
File->DirectorySector = File->SectorInCache; // store position of dir entry of that file |
File->DirectoryIndex = dir_entry; |
File->Size = Dir[dir_entry].Size; |
retvalue = 1; // mark as found |
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop |
File->SectorOfCurrCluster = 0; |
File->ByteOfCurrSector = 0; |
File->DirectorySector = curr_sector; // current sector |
File->DirectoryIndex = dir_entry; // current direntry in current sector |
File->Size = Dir[dir_entry].Size; |
direntry_exist = 1; // mark as found |
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop |
} // end of first byte of name check |
} |
dir_sector++; // search next sector |
// stop if we reached the end of the cluster or the end of the root dir |
}while((dir_sector < max_dir_sector) && (!retvalue)); |
}while((dir_sector < max_dir_sector) && (!direntry_exist)); |
|
// if we are seaching in the data area and the file not found in this cluster so take next cluster. |
if(!retvalue && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)) |
if(!direntry_exist && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)) |
{ |
end_of_directory_not_reached = GetNextCluster(File); // updates File->FirstSectorOfCurrCluster |
} |
}while((end_of_directory_not_reached) && (!retvalue)); |
return(retvalue); |
}while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no |
return(direntry_exist); |
} |
|
|
816,99 → 869,260 |
/* */ |
/* Returnvalue: Return 0 on error */ |
/****************************************************************************************************************************************/ |
u8 CreateDirectoryEntry(u8 *name, File_t *File) |
u8 CreateDirectoryEntry(u8 *dirname, u8 attrib, File_t *File) |
{ |
u32 dir_sector, max_dir_sector, curr_sector; |
u16 dir_entry = 0; |
u16 cluster = 0; |
u16 SubDirCluster, DirCluster = 0; |
u16 end_of_directory_not_reached = 0; |
u8 i = 0; |
u8 retvalue = 0; |
DirEntry_t *Dir; |
|
|
if(File == 0) return (0); |
if((File == 0) || (dirname == 0)) return (retvalue); |
// It is not checked here that the dir entry that should be created is already existent! |
|
// Dir entries can be created only in file-clusters that have |
// the dir-flag set in its attribute or within the root directory |
|
// within the root directory area its allways valid to create a directory entry |
if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector)) |
|
File->FirstSectorOfFirstCluster = 0; |
// no current directory exist therefore assume creating in the root |
if(File->DirectorySector == 0) |
{ |
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR; |
DirCluster = 0; |
File->FirstSectorOfFirstCluster = Partition.FirstRootDirSector; |
} |
// within the root directory area we can read sectors sequentially until the end of this area |
else if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector)) |
{ |
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR; |
} |
// check if the directory entry of current file has the dir-flag set |
else if(Partition.FirstDataSector <= File->DirectorySector) |
// within the data clusters we can read sectors sequentially only within the cluster |
else if((Partition.FirstDataSector <= File->DirectorySector) && (File->DirectorySector <= Partition.LastDataSector)) |
{ |
max_dir_sector = Partition.SectorsPerCluster; |
} |
else return (retvalue); // bad sector range for directory sector of the file |
// if search area is not defined yet |
if(File->FirstSectorOfFirstCluster == 0) |
{ |
// check if the directory entry of current file is existent and has the dir-flag set |
File->SectorInCache = File->DirectorySector; // update the sector number of file cache. |
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector. |
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector. |
Dir = (DirEntry_t *)File->Cache; // set pointer to directory |
if(Dir[File->DirectoryIndex].Attribute != ATTR_SUBDIRECTORY) |
{ // current file is not a directory |
return (0); |
switch(Dir[File->DirectoryIndex].Name[0]) // check if current directory exist |
{ |
case SLOT_EMPTY: |
case SLOT_DELETED: |
return (retvalue); |
break; |
default: // and is a real directory |
if((Dir[File->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY) |
{ // current file is not a directory therefore no file or subdirectory can be created here |
return (retvalue); |
} |
break; |
} |
DirCluster = Dir[File->DirectoryIndex].StartCluster; |
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(DirCluster); |
} |
else return (0); // bad sector range for directory sector of the file |
|
do // loop over all clusters of current directory |
{ |
dir_sector = 0; // reset sector counter within a new cluster |
do // loop over all sectors of a cluster or all sectors of the root directory |
{ |
curr_sector = File->FirstSectorOfCurrCluster + dir_sector; // calculate sector number |
File->SectorInCache = curr_sector; // upate the sector number of file cache. |
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector. |
Dir = (DirEntry_t *)File->Cache; // set pointer to directory |
// search all directory entries of a sector |
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++) |
{ // check if current direntry is available |
if((Dir[dir_entry].Name[0] == SLOT_EMPTY) || (Dir[dir_entry].Name[0] == SLOT_DELETED)) |
{ // a free direntry was found |
cluster = FindNextFreeCluster(File); // get the next free cluster on the disk. |
if(cluster) |
{ |
for(i = 0; i < 11; i++) Dir[dir_entry].Name[i] = name[i]; // Set dir name |
Dir[dir_entry].Attribute = File->Attribute; // Set the fileattribute to archive to reserve the directoryentry. |
Dir[dir_entry].StartCluster = cluster; // copy the location of the first datacluster to the directoryentry. |
|
SubDirCluster = FindNextFreeCluster(File); // get the next free cluster on the disk and mark it as used. |
if(SubDirCluster) |
{ |
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster; |
File->SectorOfCurrCluster = 0; |
do // loop over all clusters of current directory |
{ |
dir_sector = 0; // reset sector counter within a new cluster |
do // loop over all sectors of a cluster or all sectors of the root directory |
{ |
curr_sector = File->FirstSectorOfCurrCluster + dir_sector; // calculate sector number |
File->SectorInCache = curr_sector; // upate the sector number of file cache. |
SDC_GetSector(File->SectorInCache, File->Cache); |
Dir = (DirEntry_t *)File->Cache; // set pointer to directory |
// search all directory entries of a sector |
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++) |
{ // check if current direntry is available |
if((Dir[dir_entry].Name[0] == SLOT_EMPTY) || (Dir[dir_entry].Name[0] == SLOT_DELETED)) |
{ // a free direntry was found |
for(i = 0; i < 11; i++) Dir[dir_entry].Name[i] = dirname[i]; // Set dir name |
Dir[dir_entry].Attribute = attrib; // Set the attribute of the new directoryentry. |
Dir[dir_entry].StartCluster = SubDirCluster; // copy the location of the first datacluster to the directoryentry. |
Dir[dir_entry].Size = 0; // the new createted file has no content yet. |
SDC_PutSector(File->SectorInCache, File->Cache); // and save the sector containing new directory entry back to the sd-card. |
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(cluster); // Calculate absolute sectorposition of first datacluster. |
SDC_PutSector(File->SectorInCache, File->Cache); // write back to card |
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(SubDirCluster); // Calculate absolute sectorposition of first datacluster. |
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster; // Start reading the file with the first sector of the first datacluster. |
File->SectorOfCurrCluster = 0; // reset sector of cureen cluster |
File->ByteOfCurrSector = 0; // reset byte location within the current sector |
File->ByteOfCurrSector = 0; // reset the byte location within the current sector |
File->Attribute = attrib; // set file attribute to dir attribute |
File->Size = 0; // new file has no size |
File->DirectorySector = curr_sector; |
File->DirectoryIndex = dir_entry; |
retvalue = 1; |
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop |
if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY) // if a new directory was created then initilize the data area |
{ |
ClearCurrCluster(File); // fill cluster with zeros |
File->SectorInCache = File->FirstSectorOfFirstCluster; |
SDC_GetSector(File->SectorInCache, File->Cache); |
Dir = (DirEntry_t *)File->Cache; |
// create direntry "." to current dir |
Dir[0].Name[0] = 0x2E; |
for(i = 1; i < 11; i++) Dir[0].Name[i] = ' '; |
Dir[0].Attribute = ATTR_SUBDIRECTORY; |
Dir[0].StartCluster = SubDirCluster; |
Dir[0].Size = 0; |
// create direntry ".." to the upper dir |
Dir[1].Name[0] = 0x2E; |
Dir[1].Name[1] = 0x2E; |
for(i = 2; i < 11; i++) Dir[1].Name[i] = ' '; |
Dir[1].Attribute = ATTR_SUBDIRECTORY; |
Dir[1].StartCluster = DirCluster; |
Dir[1].Size = 0; |
SDC_PutSector(File->SectorInCache, File->Cache); |
} |
retvalue = 1; |
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop |
} |
else |
{ //no free cluster found in the fat |
return (0); |
} |
} |
dir_sector++; // search next sector |
// stop if we reached the end of the cluster or the end of the root dir |
}while((dir_sector < max_dir_sector) && (!retvalue)); |
|
// if we are seaching in the data area and the file not found in this cluster so take next cluster. |
if(!retvalue && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)) |
{ |
end_of_directory_not_reached = GetNextCluster(File); // updates File->FirstSectorOfCurrCluster |
} |
}while((end_of_directory_not_reached) && (!retvalue)); |
// Perhaps we are at the end of the last cluster of a directory file an have no free direntry found. |
// Then we would need to add a cluster to that file and create the new direntry there. |
// This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are |
// within a subdirectory of root. |
} |
return(retvalue); // return 1 if file has been created otherwise return 0. |
} |
|
/********************************************************************************************************************************************/ |
/* Function: FileExist(const u8* filename, u8 attribfilter, u8 attribmask, File_t *File); */ |
/* */ |
/* Description: This function looks for the specified filemincluding its subdirectories beginning */ |
/* in the rootdirectory of the drive. If the file is found the Filepointer properties are */ |
/* updated. */ |
/* */ |
/* Returnvalue: 1 if file is found else 0. */ |
/********************************************************************************************************************************************/ |
u8 FileExist(const u8* filename, const u8 attribfilter, const u8 attribmask, File_t *File) |
{ |
u8 *path = 0, *subpath = 0; |
u8 af, am, file_exist = 0; |
u8 dirname[11]; |
|
// if incomming pointers are useless return immediatly |
if ((filename == 0) || (File == 0)) return 0; |
|
// trace along the filepath |
path = (u8*)filename; // start a the beginning of the filename string |
File->DirectorySector = 0; // start at RootDirectory with file search |
File->DirectoryIndex = 0; |
// as long as the file was not found and the remaining path is not empty |
while((*path != 0) && !file_exist) |
{ // separate dirname and subpath from filepath string |
if((subpath = SeperateDirName(path, dirname))) |
{ |
if(*subpath == 0) |
{ // empty subpath indicates last element of dir chain |
af = attribfilter; |
am = attribmask; |
} |
else // it must be a subdirectory and no volume label |
{ |
af = ATTR_SUBDIRECTORY; |
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL; |
} |
if(!DirectoryEntryExist(dirname, af, am, File)) |
{ |
return (file_exist); // subdirectory does not exist |
} |
else |
{ |
if (*subpath == 0) |
{ |
file_exist = 1; // last element of path chain was found with the given attribute filter |
} |
} |
dir_sector++; // search next sector |
// stop if we reached the end of the cluster or the end of the root dir |
}while((dir_sector < max_dir_sector) && (!retvalue)); |
|
// if we are seaching in the data area and the file not found in this cluster so take next cluster. |
if(!retvalue && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)) |
} |
} |
else // error seperating the subpath |
{ |
end_of_directory_not_reached = GetNextCluster(File); // updates File->FirstSectorOfCurrCluster |
return file_exist; // bad subdir format |
} |
}while((end_of_directory_not_reached) && (!retvalue)); |
// Perhaps we are at the end of the last cluster of a directory file an have no free direntry found. |
// Then we would need to add a cluster to that file and create the new direntry there. |
// This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are |
// within a subdirectory of root. |
return(retvalue); // return 1 if file has been created otherwise return 0. |
path = subpath; |
subpath = 0; |
} |
return (file_exist); |
} |
|
|
/********************************************************************************************************************************************/ |
/* Function: FileCreate(const u8* filename, u8 attrib, File_t *File); */ |
/* */ |
/* Description: This function looks for the specified file including its subdirectories beginning */ |
/* in the rootdirectory of the partition. If the file is found the Filepointer properties are */ |
/* updated. If file or its subdirectories are not found they will be created */ |
/* */ |
/* Returnvalue: 1 if file was created else 0. */ |
/********************************************************************************************************************************************/ |
u8 FileCreate(const u8* filename, const u8 attrib, File_t *File) |
{ |
u8 *path = 0; |
u8 *subpath = 0; |
u8 af, am, file_created = 0; |
u8 dirname[11]; |
|
// if incomming pointers are useless return immediatly |
if ((filename == 0) || (File == 0)) return 0; |
|
// trace along the filepath |
path = (u8*)filename; // start a the beginning of the filename string |
File->DirectorySector = 0; // start at RootDirectory with file search |
File->DirectoryIndex = 0; |
// as long as the file was not created and the remaining file path is not empty |
while((*path != 0) && !file_created) |
{ // separate dirname and subpath from filepath string |
if((subpath = SeperateDirName(path, dirname))) |
{ |
if(*subpath == 0) |
{ // empty subpath indicates last element of dir chain |
af = ATTR_NONE; |
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL; // any file that is no subdir or volume label |
} |
else // it must be a subdirectory and no volume label |
{ |
af = ATTR_SUBDIRECTORY; |
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL; |
} |
if(!DirectoryEntryExist(dirname, af, am, File)) // if subdir or file is not existent |
{ // try to create subdir or file |
if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute |
if(!CreateDirectoryEntry(dirname, af, File)) |
{ // could not be created |
return(file_created); |
} |
else if (*subpath == 0) file_created = 1; // last element of path chain was created |
} |
} |
else // error seperating the subpath |
{ |
return file_created; // bad subdir format |
} |
path = subpath; |
subpath = 0; |
} |
return (file_created); |
} |
|
|
/********************************************************************************************************************************************/ |
/* Function: File_t * fopen_(u8* filename, s8 mode); */ |
/* */ |
/* Description: This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the */ |
917,9 → 1131,7 |
/* Returnvalue: The filepointer to the file or 0 if faild. */ |
/********************************************************************************************************************************************/ |
File_t * fopen_(const u8 *filename, const s8 mode) |
{ |
u8 name[11]; |
u8 *filepath = 0; |
{ |
File_t *File = 0; |
u8 i; |
|
936,7 → 1148,8 |
// if no unused file pointer was found return 0 |
if(File == 0) return(File); |
|
// initialize values |
// now we have found a free filepointer and claimed it |
// so let initiate its property values |
File->FirstSectorOfFirstCluster = 0; // Sectorpointer to the first sector of the first datacluster of the file. |
File->FirstSectorOfCurrCluster = 0; // Pointer to the cluster which is edited at the moment. |
File->SectorOfCurrCluster = 0; // The sector which is edited at the moment (cluster_pointer + sector_index). |
949,50 → 1162,66 |
File->DirectoryIndex = 0; // the index to the directoryentry within the specified sector. |
File->Attribute = 0; // the attribute of the file opened. |
|
// trace along the filepath by checking if the directories |
filepath = (u8*)filename; // start a the beginning of the filename string |
File->DirectorySector = Partition.FirstRootDirSector; // Root of RootDirectory is Root |
File->FirstSectorOfCurrCluster = Partition.FirstRootDirSector; // start search in RootDirectory |
File->Attribute = ATTR_SUBDIRECTORY; //check for directory |
while(*filepath != 0) |
{ |
if(SeperateDirName(filepath, name, filepath)) // separate dirname from filepath string |
// check if a real file (no directory) to the given filename exist |
if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, File)) |
{ // file exist |
switch(mode) // check mode |
{ |
if(!DirectoryEntryExist(name, File)) |
{ |
goto errorout; // subdirectory does not exist |
} |
case 'a': // if mode is: append to file |
if((File->Attribute & ATTR_READONLY) == ATTR_READONLY) |
{ // file is marked as readonly --> do not open this file |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
} |
else |
{ // file is not marked as read only --> goto end of file |
fseek_(File, 0, SEEK_END); // point to the end of the file |
} |
break; |
case 'w': // if mode is: write to file |
if((File->Attribute & ATTR_READONLY) == ATTR_READONLY) |
{ // file is marked as readonly --> do not open this file |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
} |
else |
{ // file is not marked as read only --> goto start of file |
fseek_(File, 0, SEEK_SET); |
} |
break; |
case 'r': // if mode is: read from to file |
// goto end of file |
fseek_(File, 0, SEEK_SET); |
break; |
default: // other modes are not supported |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
break; |
} |
else // error seperating the subpath |
{ |
goto errorout; // bad subdir format |
} |
} |
// now name cointains the name of the file at the end of the filepath |
File->Attribute = ATTR_ARCHIVE; |
if(DirectoryEntryExist(name, File)) // file exist |
{ |
if(mode == 'a') // if mode is: append to file |
{ |
fseek_(File, 0, SEEK_END); // point to the end of the file |
} |
// else w /r ?? |
return(File); |
} |
else // file does not exist |
{ |
if((mode == 'a') || (mode == 'w')) |
switch(mode) // check mode |
{ |
if(CreateDirectoryEntry(name, File)) // Could an entry for the new file in the directory be created? |
{ |
return(File); |
} |
// else directory entry could be created at the current location --> error |
case 'a': |
case 'w': // if mode is write or append |
// try to create the file |
if(!FileCreate(filename, ATTR_ARCHIVE, File)) |
{ // if it could not be created |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
} |
break; |
case 'r': // else opend for 'r' |
default: // of unsupported mode |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
break; |
} |
// else opend for 'r' and file is not existent --> error |
return(File); |
} |
|
errorout: |
// we should never come to this point |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
return(File); |
1132,7 → 1361,6 |
return(c); |
} |
|
|
/********************************************************************************************************************************************/ |
/* Function: fputc_( const s8 c, File *File); */ |
/* */ |