370 lines
15 KiB
C

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : dir.c *
* Description : The functions of dir.c are part of fs.c, they deal with all *
* the directory specific stuff. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
* *
* mthomas: applied patch for sf.net bug-tracker: *
* - for(c=fs->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->volumeId.RootEntryCount/32);c++){ *
* + for(c=fs->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->volumeId.RootEntryCount/16);c++){ *
* *
* mthomas: testing - modified byte-array access to use extract.h-functions *
* to avoid aligment warnings with arm-elf-gcc *
\*****************************************************************************/
/*****************************************************************************/
#include "dir.h"
/*****************************************************************************/
/* ****************************************************************************
* void dir_getFileStructure(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
* Description: This function stores the filerecord located at loc in filerec.
* It fetches the required sector for this.
* Return value: void
*/
void dir_getFileStructure(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
{
euint8 *buf;
buf=part_getSect(fs->part,loc->Sector,IOM_MODE_READONLY);
*filerec=*(((FileRecord*)buf)+loc->Offset);
part_relSect(fs->part,buf);
}
/*****************************************************************************/
/* ****************************************************************************
* void dir_createDirectoryEntry(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
* Description: This function writes the filerecord stored in filerec to disc at
* location loc.
* Return value: void
*/
void dir_createDirectoryEntry(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
{
euint8 *buf;
buf = part_getSect(fs->part,loc->Sector,IOM_MODE_READWRITE);
memCpy(filerec,buf+(loc->Offset*sizeof(*filerec)),sizeof(*filerec));
part_relSect(fs->part,buf);
}
/*****************************************************************************/
/* ****************************************************************************
* void dir_createDefaultEntry(FileSystem *fs,FileRecord *filerec,eint8* fatfilename)
* Description: This function fills in a filerecord with safe default values, and
* a given fatfilename. If your system has a means of knowing time, here is an
* excellent place to apply it to the filerecord.
* Return value: void
*/
void dir_createDefaultEntry(FileSystem *fs,FileRecord *filerec,eint8* fatfilename)
{
memCpy(fatfilename,filerec->FileName,11);
filerec->Attribute=0x00;
filerec->NTReserved=0x00;
filerec->MilliSecTimeStamp=0x00;
filerec->CreatedTime=time_getTime();
filerec->CreatedDate=time_getDate();
filerec->AccessDate=filerec->CreatedDate;
filerec->FirstClusterHigh=0x0000;
filerec->WriteTime=filerec->CreatedTime;
filerec->WriteDate=filerec->CreatedDate;
filerec->FirstClusterLow=0x0000;
filerec->FileSize=0x00000000;
}
/*****************************************************************************/
/* ****************************************************************************
* void dir_setFirstCluster(File *file,euint32 cluster_addr)
* Description: This function requires modification to release it from
* depending on the file object.
* Return value:
*/
void dir_setFirstCluster(FileSystem *fs,FileLocation *loc,euint32 cluster_addr)
{
euint8 *buf;
buf = part_getSect(fs->part,loc->Sector,IOM_MODE_READWRITE);
(((FileRecord*)buf)+loc->Offset)->FirstClusterHigh=cluster_addr>>16;
(((FileRecord*)buf)+loc->Offset)->FirstClusterLow=cluster_addr&0xFFFF;
part_relSect(fs->part,buf);
}
/*****************************************************************************/
/* ****************************************************************************
* void dir_setFileSize(FileSystem *fs, FileLocation *loc,euint32 numbytes)
* Description: This function changes the filesize recorded at loc->Sector
* to 'numbytes'.
* Return value: void
*/
void dir_setFileSize(FileSystem *fs, FileLocation *loc,euint32 numbytes)
{
euint8 *buf;
buf = part_getSect(fs->part,loc->Sector,IOM_MODE_READWRITE);
(((FileRecord*)buf)+loc->Offset)->FileSize=numbytes;
part_relSect(fs->part,buf);
}
/*****************************************************************************/
/* ****************************************************************************
* esint8 dir_updateDirectoryEntry(FileSystem *fs,FileRecord *entry,FileLocation *loc))
* This function changes the entire entity stores at loc to the data recorded
* in entry. This is for custom updates to the directoryentry.
* Return value: 0 on success, -1 on failure
*/
esint8 dir_updateDirectoryEntry(FileSystem *fs,FileRecord *entry,FileLocation *loc)
{
euint8 *buf;
buf = part_getSect(fs->part,loc->Sector,IOM_MODE_READWRITE);
memCpy(entry,buf+(loc->Offset*sizeof(*entry)),sizeof(*entry));
part_relSect(fs->part,buf);
return(0);
}
/* ****************************************************************************
* euint32 dir_findFileinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc)
* This function searches for a given fatfilename in the buffer provided.
* It will iterate through the 16 direntry's in the buffer and searches
* for the fatfilename. If found, it will store the offset and attribute
* entry of the directoryrecord in the loc structure.
* If loc is 0, then it's members are not touched.
* Return value: This function returns 0 when it cannot find the file,
* if it can find the file it will return the first cluster number.
*/
euint32 dir_findFileinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc)
{
FileRecord fileEntry;
euint8 c;
for(c=0; c<16; c++)
{
fileEntry = *(((FileRecord*)buf) + c);
/* Check if the entry is for short filenames */
if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) )
{
if( strMatch((eint8*)fileEntry.FileName,fatname,11) == 0 )
{
/* The entry has been found, return the location in the dir */
if(loc)loc->Offset = c;
if(loc)loc->attrib = fileEntry.Attribute;
if((((euint32 )fileEntry.FirstClusterHigh)<<16)+ fileEntry.FirstClusterLow==0){
return(1); /* Lie about cluster, 0 means not found! */
}else{
return
(
(((euint32 )fileEntry.FirstClusterHigh)<<16)
+ fileEntry.FirstClusterLow
);
}
}
}
}
return(0);
}
/* ****************************************************************************
* euint32 dir_findFreeEntryinBuf(euint8* buf, FileLocation *loc)
* This function searches for a free entry in a given sector 'buf'.
* It will put the offset into the loc->Offset field, given that loc is not 0.
* Return value: 1 when it found a free spot, 0 if it hasn't.
*/
euint32 dir_findFreeEntryinBuf(euint8* buf, FileLocation *loc)
{
FileRecord fileEntry;
euint8 c;
for(c=0;c<16;c++){
fileEntry = *(((FileRecord*)buf) + c);
if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) ){
if(fileEntry.FileName[0] == 0x00 ||
fileEntry.FileName[0] == 0xE5 ){
if(loc)loc->Offset=c;
return(1);
}
}
}
return(0);
}
/* ****************************************************************************
* euint32 dir_findinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc)
* Description: This function searches for a given fatfilename in a buffer.
* Return value: Returns 0 on not found, and the firstcluster when the name is found.
*/
euint32 dir_findinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc, euint8 mode)
{
switch(mode){
case DIRFIND_FILE:
return(dir_findFileinBuf(buf,fatname,loc));
break;
case DIRFIND_FREE:
return(dir_findFreeEntryinBuf(buf,loc));
break;
default:
return(0);
break;
}
return(0);
}
/*****************************************************************************/
/* ****************************************************************************
* euint32 dir_findinCluster(FileSystem *fs,euint32 cluster,eint8 *fatname, FileLocation *loc, euint8 mode)
* This function will search for an existing (fatname) or free directory entry
* in a full cluster.
* Return value: 0 on failure, firstcluster on finding file, and 1 on finding free spot.
*/
euint32 dir_findinCluster(FileSystem *fs,euint32 cluster,eint8 *fatname, FileLocation *loc, euint8 mode)
{
euint8 c,*buf=0;
euint32 fclus;
for(c=0;c<fs->volumeId.SectorsPerCluster;c++){
buf = part_getSect(fs->part,fs_clusterToSector(fs,cluster)+c,IOM_MODE_READONLY);
if((fclus=dir_findinBuf(buf,fatname,loc,mode))){
if(loc)loc->Sector=fs_clusterToSector(fs,cluster)+c;
part_relSect(fs->part,buf);
return(fclus);
}
part_relSect(fs->part,buf); /* Thanks Mike ;) */
}
return(0);
}
/* ****************************************************************************
* euint32 dir_findinDir(FileSystem *fs, eint8* fatname,euint32 firstcluster, FileLocation *loc, euint8 mode)
* This function will search for an existing (fatname) or free directory entry
* in a directory, following the clusterchains.
* Return value: 0 on failure, firstcluster on finding file, and 1 on finding free spot.
*/
euint32 dir_findinDir(FileSystem *fs, eint8* fatname,euint32 firstcluster, FileLocation *loc, euint8 mode)
{
euint32 c=0,cluster;
ClusterChain Cache;
Cache.DiscCluster = Cache.FirstCluster = firstcluster;
Cache.LogicCluster = Cache.LastCluster = Cache.Linear = 0;
if(firstcluster <= 1){
return(dir_findinRootArea(fs,fatname,loc,mode));
}
while(!fat_LogicToDiscCluster(fs,&Cache,c++)){
if((cluster=dir_findinCluster(fs,Cache.DiscCluster,fatname,loc,mode))){
return(cluster);
}
}
return(0);
}
/* ****************************************************************************
* euint32 dir_findinDir(FileSystem *fs, eint8* fatname,euint32 firstcluster, FileLocation *loc, euint8 mode)
* This function will search for an existing (fatname) or free directory entry
* in the rootdirectory-area of a FAT12/FAT16 filesystem.
* Return value: 0 on failure, firstcluster on finding file, and 1 on finding free spot.
*/
euint32 dir_findinRootArea(FileSystem *fs,eint8* fatname, FileLocation *loc, euint8 mode)
{
euint32 c,fclus;
euint8 *buf=0;
if((fs->type != FAT12) && (fs->type != FAT16))return(0);
#warning "inofficial find in root patch included"
/* for(c=fs->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->volumeId.RootEntryCount/32);c++){*/
for(c=fs->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->volumeId.RootEntryCount/16);c++) {
buf = part_getSect(fs->part,c,IOM_MODE_READONLY);
if((fclus=dir_findinBuf(buf,fatname,loc,mode))){
if(loc)loc->Sector=c;
part_relSect(fs->part,buf);
return(fclus);
}
part_relSect(fs->part,buf);
}
part_relSect(fs->part,buf);
return(0);
}
/* ****************************************************************************
* esint8 dir_getFatFileName(eint8* filename, eint8* fatfilename)
* This function will take a full directory path, and strip off all leading
* dirs and characters, leaving you with the MS-DOS notation of the actual filename.
* Return value: 1 on success, 0 on not being able to produca a filename
*/
esint8 dir_getFatFileName(eint8* filename, eint8* fatfilename)
{
eint8 ffnamec[11],*next,nn=0;
memClr(ffnamec,11); memClr(fatfilename,11);
next = filename;
if(*filename=='/')next++;
while((next=file_normalToFatName(next,ffnamec))){
memCpy(ffnamec,fatfilename,11);
nn++;
}
if(nn)return(1);
return(0);
}
/* ****************************************************************************
* esint8 dir_addCluster(FileSystem *fs,euint32 firstCluster)
* This function extends a directory by 1 cluster + optional the number of
* clusters you want pre-allocated. It will also delete the contents of that
* cluster. (or clusters)
* Return value: 0 on success, -1 on fail
*/
esint8 dir_addCluster(FileSystem *fs,euint32 firstCluster)
{
euint32 lastc,logicalc;
ClusterChain cache;
fs_initClusterChain(fs,&cache,firstCluster);
if(fat_allocClusterChain(fs,&cache,1)){
return(-1);
}
lastc = fs_getLastCluster(fs,&cache);
if(CLUSTER_PREALLOC_DIRECTORY){
if(fat_allocClusterChain(fs,&cache,CLUSTER_PREALLOC_DIRECTORY)){
return(-1);
}
logicalc = fat_DiscToLogicCluster(fs,firstCluster,lastc);
while(!fat_LogicToDiscCluster(fs,&cache,++logicalc)){
fs_clearCluster(fs,cache.DiscCluster);
}
}else{
fs_clearCluster(fs,lastc);
}
return(0);
}