📄 fat_write.c
字号:
}
}
deIdx = 0;
//clear name strings
dir.sname[0] = 0;
dir.name[0] = 0;
} else {
record[j] = 3;
deIdx = 0;
}
break;
case 2: record[j] = 2; //long name
deSec[deIdx] = theSector;
deOfs[deIdx] = dirPos;
deIdx++;
break;
case 3: record[j] = 0; //empty
deIdx = 0;
break;
}
dirPos += 32; //directory entry of size 32 bytes
j++;
}
}
//indicate inconsistency
if (j>= maxRecord) {
j++;
}
return j;
}
/*
check wether the new direntries (note: one file have at least 2 direntries for 1 SFN and 1..n LFN)
fit into the current directory space.
Enlarges the directory space if needed and possible (note: root dirspace can't be enlarged for fat12 and fat16)
startCluster - valid start cluster of dirpace or 0 for the root directory
entryCount - number of direntries of the filename (at least 2)
entryIndex - index where to store new direntries
direntrySize - number of all direntries in the directory
*/
int enlargeDirentryClusterSpace(fat_bpb* bpb, unsigned int startCluster, int entryCount, int entryIndex, int direntrySize) {
int ret;
int dirSector;
unsigned int startSector;
int clusterMod;
int i;
int maxSector;
int entriesPerSector;
int chainSize;
unsigned int currentCluster;
unsigned int newCluster;
i = entryIndex + direntrySize;
XPRINTF("cur=%d ecount=%d \n", i, entryCount);
//we don't need to enlarge directory cluster space
if (i <= entryCount) return 0; //direntry fits into current space
entriesPerSector = bpb->sectorSize / 32;
maxSector = i / entriesPerSector;
if (i%entriesPerSector) {
maxSector++;
}
chainSize = fat_getDirentrySectorData(bpb, &startCluster, &startSector, &dirSector);
XPRINTF("maxSector=%d dirSector=%d\n", maxSector, dirSector);
if (maxSector<=dirSector) return 0;
//Root directory of FAT12 or FAT16 - space can't be enlarged!
if (startCluster == 0 && bpb->fatType < FAT32) {
return -EMLINK; //too many direntries in the root directory
}
//in the cbuf we have the cluster chain
#ifdef DEBUG
fat_dumpClusterChain(cbuf, chainSize, 0);
#endif
//get last cluster of the cluster chain
currentCluster = cbuf[chainSize-1];
XPRINTF("current (last) cluster=%d \n", currentCluster);
//get 1 cluster from cluster stack and append the chain
newCluster = fat_getFreeCluster(bpb, currentCluster);
XPRINTF("new cluster=%d \n", newCluster);
fat_invalidateLastChainResult(); //prevent to misuse current (now updated) cbuf
//if new cluster cannot be allocated
if (newCluster == 0) {
return -ENOSPC;
}
// now clean the directory space
startSector = fat_cluster2sector(bpb, newCluster);
for (i = 0; i < bpb->clusterSize; i++) {
ret = ALLOC_SECTOR(startSector + i, sbuf);
memset(sbuf, 0 , bpb->sectorSize); //fill whole sector with zeros
ret = WRITE_SECTOR(startSector + i);
if (ret < 0) return -EIO;
}
return 1; // 1 cluster allocated
}
/*
Create direntries of the long and short filename to the supplied buffer.
lname : long name
sname : short name
directory : 0-file, 1-directory
buffer : start of the data buffer where to store direntries
cluster : start cluster of the file/directory
returns the number of the direntries (3 means: 2 entries for long name + 1 entry for short name)
note: the filesize set in the direntry is 0 (for both directory and file)
*/
int createDirentry(unsigned char* lname, unsigned char* sname, char directory, unsigned int cluster, unsigned char* buffer) {
int i;
int lsize;
int nameSize;
unsigned char chsum;
lsize = getDirentrySize(lname) - 1;
chsum = computeNameChecksum(sname);
nameSize = strlen((const char*) lname);
//if the long name is longer than 8.3 chars then more than 1 lfn direntry have to be made
for (i = 0; i <= lsize; i++) {
setLfnEntry(lname, nameSize, chsum, buffer, lsize-i, lsize);
}
lsize++;
//now create direntry of the short name right behind the long name direntries
setSfnEntry(sname, directory, buffer + (lsize * 32), cluster);
return lsize + 1;
}
/*
Create empty directory space with two SFN direntries:
1) current directory "."
2) parent directory ".."
*/
int createDirectorySpace(fat_bpb* bpb, unsigned int dirCluster, unsigned int parentDirCluster) {
int i,j;
int ret;
unsigned int startSector;
unsigned char name[11];
//we do not mess with root directory
if (dirCluster < 2) {
return -EFAULT;
}
for (i = 0; i< 11; i++) name[i] = 32;
name[0] = '.';
setSfnEntry(name, 1, tbuf, dirCluster);
name[1] = '.';
setSfnEntry(name, 1, tbuf + 32, parentDirCluster);
#ifdef DEBUG
fat_dumpSectorHex(tbuf, 64);
#endif
//we create directory space inside one cluster. No need to worry about
//large dir space spread on multiple clusters
startSector = fat_cluster2sector(bpb, dirCluster);
XPRINTF("I: create dir space: cluster=%d sector=%d (%d) \n", dirCluster, startSector, startSector * bpb->sectorSize);
//go through all sectors of the cluster
for (i = 0; i < bpb->clusterSize; i++) {
ret = READ_SECTOR(startSector + i, sbuf);
if (ret < 0) {
printf("FAT writer: read directory sector failed ! sector=%i\n", startSector + i);
return -EIO;
}
memset(sbuf, 0, bpb->sectorSize); //clean the sector
if (i == 0) {
memcpy(sbuf, tbuf, 64);
}
ret = WRITE_SECTOR(startSector + i);
if (ret < 0) {
printf("FAT writer: write directory sector failed ! sector=%i\n", startSector + i);
return -EIO;
}
}
}
/*
save direntries stored in dbuf to the directory space on the disk
startCluster - start cluster of the directory space
dbuf - direntry buffer
entrySize - number of direntries stored in the dbuf
entryIndex - index of the direntry start in the directory space
retSector - contains sector number of the direntry (output)
retOffset - contains byte offse of the SFN direntry from start of the sector (output)
the reason is to speed up modification of the SFN (size of the file)
*/
int saveDirentry(fat_bpb* bpb, unsigned int startCluster, unsigned char * dbuf, int entrySize, int entryIndex, unsigned int* retSector, int* retOffset) {
int i, j;
int dirSector;
unsigned int startSector;
unsigned int theSector;
int cont;
int ret;
int dirPos;
int clusterMod;
int entryEndIndex;
int writeFlag;
cont = 1;
clusterMod = bpb->clusterSize - 1;
//clear name strings
entryEndIndex = entryIndex + entrySize;
j = 0;
fat_getDirentrySectorData(bpb, &startCluster, &startSector, &dirSector);
XPRINTF("dirCluster=%i startSector=%i (%i) dirSector=%i \n", startCluster, startSector, startSector * Size_Sector, dirSector);
//go through first directory sector till the max number of directory sectors
//or stop when no more direntries detected
for (i = 0; i < dirSector && cont; i++) {
theSector = startSector + i;
ret = READ_SECTOR(theSector, sbuf);
if (ret < 0) {
printf("FAT writer: read directory sector failed ! sector=%i\n", theSector);
return -EIO;
}
XPRINTF("read sector ok, scanning sector for direntries...\n");
//prepare next sector: get correct sector from cluster chain buffer
if ((startCluster != 0) && (i % bpb->clusterSize == clusterMod)) {
startSector = fat_cluster2sector(bpb, cbuf[(i / bpb->clusterSize) + 1]);
startSector -= (i+1);
}
dirPos = 0;
writeFlag = 0;
// go through start of the sector till the end of sector
while (dirPos < bpb->sectorSize) {
if (j >=entryIndex && j < entryEndIndex) {
memcpy(sbuf + dirPos, dbuf + ((j-entryIndex)*32), 32);
writeFlag++;
//SFN is stored
if (j == entryEndIndex-1) {
*retSector = theSector;
*retOffset = dirPos;
}
}
//sbuf + dirPos
dirPos += 32; //directory entry of size 32 bytes
j++;
}
//store modified sector
if (writeFlag) {
ret = WRITE_SECTOR(theSector);
if (ret < 0) {
printf("FAT writer: write directory sector failed ! sector=%i\n", theSector);
return -EIO;
}
}
if (j >= entryEndIndex) {
cont = 0; //do not continue
}
}
return j;
}
/*
- create/convert long name to short name
- analyse directory space
- enlarge directory space
- save direntries
lname - long name
directory - 0-> create file 1->create directory
escapeNoExist - 0->allways create file 1->early exit if file doesn't exist
startCluster - directory space start cluster (set to zero for root directory)
retSector - SFN sector - sector of the SFN direntry (output)
retOffset - byte offset of the SFN direntry counting from the start of the sector (output)
*/
int fat_modifyDirSpace(fat_bpb* bpb, unsigned char* lname, char directory, char escapeNotExist, unsigned int* startCluster, unsigned int* retSector, int* retOffset) {
int ret;
int i;
unsigned char sname[12]; //short name 8+3 + terminator
unsigned int newCluster;
int entryCount;
int compressShortName;
int entryIndex;
int direntrySize;
//memo buffer for each direntry - up to 1024 entries in directory
// 7 6 5 4 3 2 | 1 0
// ------------+-----
// SEQ HI/LO | ID
// ------------------
// ID : 0 - entry is empty or deleted
// 1 - sfn entry
// 2 - lfn entry
// 3 - other entry (volume label etc.)
// SEQ: sequence number of the short filename.
// if our long filename is "Quitelongname.txt" then
// seq for existing entry:
// ABCD.TXT seq = 0 (no sequence number in name and name doesn't match)
// ABCDEF~1.TXT seq = 0 (because the short names doesn't match)
// QUITELON.TXT seq = 0 (again the short name doesn't match)
// QUITEL~1.JPG seq = 0 (name match but extension desn't match)
// QUITEL~1.TXT seq = 1 (both name and extension match - sequence number 1)
// QUITE~85.TXT seq = 85 ( dtto. ^^^^)
// If the sfn has sequence it means the filename should be long
// and preceeding entry should be lfn. In this case the preceeding (lfn)
// entry seq holds the high 6 bites of the whole sequence. If preceding
// entry is another sfn direntry then we report error (even if it might be
// (in some rare occasions) correct directory structure).
unsigned char entry[DIRENTRY_COUNT];
memset(entry, 0, DIRENTRY_COUNT);
sname[11] = 0;
//create short name from long name
ret = createShortNameMask(lname,sname);
if (ret < 0) {
XPRINTF("E: short name invalid!\n");
return ret;
}
compressShortName = ret;
#ifdef DEBUG
printf("compressShortName = %i\n", compressShortName);
#endif
//get information about existing direntries (palcement of the empty/reusable direntries)
//and sequence nubers of the short filenames
ret = fat_fillDirentryInfo(bpb, lname, sname, directory, startCluster, entry, DIRENTRY_COUNT, retSector, retOffset);
if (ret < 0) {
XPRINTF("E: direntry data invalid!\n");
return ret;
}
//ret 0 means that exact filename/directory already exist
if (ret == 0) {
return ret;
}
//exact filename not exist and we want to report it
if (escapeNotExist) {
return -ENOENT;
}
if (ret > DIRENTRY_COUNT) {
XPRINTF("W: Direntry count is larger than number of records!\n");
ret = DIRENTRY_COUNT;
}
entryCount = ret;
XPRINTF("I: direntry count=%d\n", entryCount);
#ifdef DEBUG
for (i = 0; i < entryCount; i++) printf("%d ", entry[i]);
printf("\n");
#endif
if (compressShortName) {
setShortNameSequence(entry, entryCount, sname);
}
XPRINTF("I: new short name='%s' \n", sname);
//find the offset (index) of the direntry space where to put this direntry
entryIndex = getDirentryStoreOffset(entry, entryCount, lname, &direntrySize);
XPRINTF("I: direntry store offset=%d\n", entryIndex);
//if the direntry offset excede current space of directory clusters
//we have to add one cluster to directory space
ret = enlargeDirentryClusterSpace(bpb, *startCluster, entryCount, entryIndex, direntrySize);
XPRINTF("I: enlarge direntry cluster space ret=%d\n", ret);
if (ret < 0) {
return ret;
}
//get new cluster for file/directory
newCluster = fat_getFreeCluster(bpb, 0);
if (newCluster == 0) {
return -EFAULT;
}
XPRINTF("I: new file/dir cluster=%d\n", newCluster);
//create direntry data to temporary buffer
ret = createDirentry(lname, sname, directory, newCluster, tbuf);
XPRINTF("I: create direntry to buf ret=%d\n", ret);
if (ret < 0) {
return ret;
}
direntrySize = ret;
#ifdef DEBUG
fat_dumpSectorHex(tbuf, direntrySize * 32);
#endif
// return -1;
//now store direntries into the directory space
ret = saveDirentry(bpb, *startCluster, tbuf, direntrySize, entryIndex, retSector, retOffset);
XPRINTF("I: save direntry ret=%d\n", ret);
if (ret < 0) {
return ret;
}
//create empty directory structure
if (directory) {
ret = createDirectorySpace(bpb, newCluster, *startCluster);
XPRINTF("I: create directory space ret=%d\n", ret);
if (ret < 0) {
return ret;
}
}
return 1;
}
/*
Check wether directory space contain any file or directory
startCluster - start cluster of the directory space
returns: 0 - false - directory space contains files or directories (except '.' and '..')
1 - true - directory space is empty or contains deleted entries
-X - error
*/
int checkDirspaceEmpty(fat_bpb* bpb, unsigned int startCluster, unsigned char* entry) {
int ret;
int i;
unsigned char sname[12]; //short name 8+3 + terminator
int entryCount;
// int entryIndex;
int direntrySize;
unsigned int retSector;
int retOffset;
XPRINTF("I: checkDirspaceEmpty directory cluster=%d \n", startCluster);
if (startCluster < 2) { // do not check root directory!
return -EFAULT;
}
memset(entry, 0, DIRENTRY_COUNT);
sname[0] = 0;
ret = fat_fillDirentryInfo(bpb, sname, sname, 1, &startCluster, entry, DIRENTRY_COUNT, &retSector, &retOffset);
if (ret > DIRENTRY_COUNT) {
XPRINTF("W: Direntry count is larger than number of records! directory space cluster =%d maxRecords=%d\n", startCluster, DIRENTRY_COUNT);
ret = DIRENTRY_COUNT;
}
entryCount = ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -