370 lines
15 KiB
C
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);
|
|
}
|
|
|
|
|