📄 fat_write.c
字号:
dsfn->timeCreate[1] = tmpClk[1];
dsfn->dateCreate[0] = tmpClk[2];
dsfn->dateCreate[1] = tmpClk[3];
dsfn->dateAccess[0] = tmpClk[2];
dsfn->dateAccess[1] = tmpClk[3];
}
//set date & time of modification
if (mode & DATE_MODIFY) {
dsfn->timeWrite[0] = tmpClk[0];
dsfn->timeWrite[1] = tmpClk[1];
dsfn->dateWrite[0] = tmpClk[2];
dsfn->dateWrite[1] = tmpClk[3];
}
}
/*
fill the SFN (short filename) direntry
*/
void setSfnEntry(unsigned char* shortName, char directory, unsigned char *buffer, unsigned int cluster) {
int i,j;
fat_direntry_sfn* dsfn;
dsfn = (fat_direntry_sfn*) buffer;
//name + ext
for (i = 0; i < 8; i++) dsfn->name[i] = shortName[i];
for (i = 0; i < 3; i++) dsfn->ext[i] = shortName[i+8];
if (directory > 0) {
dsfn->attr = 16; //directory bit set
} else {
dsfn->attr = 32; //ordinary file + archive bit set
}
dsfn->reservedNT = 0;
dsfn->clusterH[0] = (cluster & 0xFF0000) >> 16;
dsfn->clusterH[1] = (cluster & 0xFF000000) >> 24;
dsfn->clusterL[0] = (cluster & 0x00FF);
dsfn->clusterL[1] = (cluster & 0xFF00) >> 8;
//size is zero - because we don't know the filesize yet
for (i = 0; i < 4; i++) dsfn->size[i] = 0;
setSfnDate(dsfn, DATE_CREATE + DATE_MODIFY);
}
/*
Create short name by squeezing long name into the 8.3 name boundaries
lname - existing long name
sname - buffer where to store short name
returns: 0 if longname completely fits into the 8.3 boundaries
1 if long name have to be truncated (ie. INFORM~1.TXT
<0 if invalid long name detecte
*/
int createShortNameMask(unsigned char* lname, unsigned char* sname) {
int i;
int size;
int j;
int fit;
if (lname[0] == '.') {
return -EINVAL;
}
fit = 0;
//clean short name by putting space
for (i = 0; i < 11; i++) sname[i] = 32;
XPRINTF("Clear short name ='%s'\n", sname);
//detect number of dots and space characters in the long name
j = 0;
for (i = 0; lname[i] != 0; i++) {
if (lname[i] == '.') j++; else
if (lname[i] == 32 ) j+=2;
}
//long name contains no dot or one dot and no space char
if (j <= 1) fit++;
//XPRINTF("fit1=%d j=%d\n", fit, j);
//store name
for (i = 0; lname[i] !=0 && lname[i] != '.' && i < 8; i++) {
sname[i] = toUpperChar(lname[i]);
//short name must not contain spaces - replace space by underscore
if (sname[i] == 32) sname[i]='_';
}
//check wether last char is '.' and the name is shorter than 8
if (lname[i] == '.' || lname[i] == 0) {
fit++;
}
//XPRINTF("fit2=%d\n", fit);
//find the last dot "." - filename extension
size = strlen((const char*)lname);
size--;
for (i = size; i > 0 && lname[i] !='.'; i--);
if (lname[i] == '.') {
i++;
for (j=0; lname[i] != 0 && j < 3; i++, j++) {
sname[j+8] = toUpperChar(lname[i]);
}
//no more than 3 characters of the extension
if (lname[i] == 0) fit++;
} else {
//no dot detected in the long filename
fit++;
}
// XPRINTF("fit3=%d\n", fit);
// XPRINTF("Long name=%s Short name=%s \n", lname, sname);
//all 3 checks passed - the long name fits in the short name without restrictions
if (fit == 3) {
XPRINTF("Short name is loseles!\n");
return 0;
}
//one of the check failed - the short name have to be 'sequenced'
//do not allow spaces in the short name
for (i = 0; i < 8;i++) {
if (sname[i] == 32) sname[i] = '_';
}
return 1;
}
/*
separate path and filename
fname - the source (merged) string (input)
path - separated path (output)
name - separated filename (output)
*/
int separatePathAndName(const char* fname, unsigned char* path, unsigned char* name) {
int i;
int lastSeparator;
int nameIndex;
lastSeparator = 0;
nameIndex = 0;
for (i = 0; fname[i] != 0; i++) {
path[i] = fname[i];
if (fname[i] == '/' || fname[i] == '\\') {
lastSeparator = i;
nameIndex = 0;
} else {
if (nameIndex >= FAT_MAX_NAME-1) {
return -ENAMETOOLONG;
}
name[nameIndex] = fname[i];
nameIndex++;
}
}
//terminate strings
path[lastSeparator+1] = 0;
name[nameIndex] = 0;
return 1;
}
/*
get the sequence number from existing direntry name
*/
int getShortNameSequence(unsigned char* name, unsigned char* ext, unsigned char* sname) {
int i,j;
unsigned char* tmp;
unsigned char buf[8];
//at first: compare extensions
//if extensions differ then filenames are diffrerent and seq is 0
tmp = sname+8;
for (i = 0; i < 3; i++) {
if (ext[i] != tmp[i]) return 0;
}
//at second: find tilde '~' character (search backward from the end)
for (i = 7; i > 0 && name[i] !='~'; i--);
if (i == 0) return 0; // tilde char was not found or is at first character
//now compare the names - up to '~' position
//if names differ then filenames are different;
for (j=0; j < i;j++) {
if (name[j] != sname[j]) return 0;
}
//if we get to this point we know that extension and name match
//now get the sequence number behind the '~'
for (j = i+1; j<8; j++) buf[j-i-1] = name[j];
buf[j-i-1] = 0; //terminate
XPRINTF("found short name sequence number='%s' \n", buf);
return strtol((const char*)buf, NULL, 10);
}
/*
set the short name sequence number
*/
int setShortNameSequence(unsigned char* entry, int maxEntry, unsigned char* sname) {
char number[8];
unsigned char *buf;
int i,j;
int maxSeq;
int hit;
int seq;
int cont;
seq = 0;
maxSeq = 0;
hit = 0;
//search the entries for sequence number
for (i = 0; i < maxEntry; i++) {
seq = (entry[i] & 0xFC) >> 2;
if (seq && i && (entry[i-1] & 0x03) == 2) { // seq != 0 && i != 0 && prceeding entry is long name
seq += (entry[i-1] & 0xFC) << 4;
}
if (seq > maxSeq) maxSeq = seq; //find max sequence number
if (seq) hit++; //find any sequence number
}
//check how many sequence numbers we have found and the highest sequence number.
//if we get: hit==3 and maxSeq==120 then try to find unassigned sequence number
if (hit < maxSeq) {
cont = 1;
for (j = 0; j < maxSeq && cont; j++) {
//search the entries for sequence number
for (i = 0; i < maxEntry && cont; i++) {
seq = (entry[i] & 0xFC) >> 2;
if (seq && i && (entry[i-1] & 0x03) == 2) { // seq != 0 && i != 0 && prceeding entry is long name
seq += (entry[i-1] & 0xFC) << 4;
}
if (seq==j) cont = 0; //we found the sequence nuber - do not continue
}
if (cont == 1) { //the sequence number was missing in the entries
seq = j;
}
cont = 1-cont; //set continue flag according the search result;
}
} else {
seq = maxSeq + 1;
}
memset(number, 0, 8);
sprintf(number, "%d",seq);
j = strlen(number);
buf = sname + 7 - j;
buf[0] = '~';
buf++;
for (i = 0; i < j; i++) buf[i] = number[i];
return 0;
}
/*
find space where to put the direntry
*/
int getDirentryStoreOffset(unsigned char* entry, int entryCount, unsigned char* lname, int* direntrySize ) {
int i;
int size;
int tightIndex;
int looseIndex;
int cont;
int id;
int slotStart;
int slotSize;
//direntry size for long name + 1 additional direntry for short name
size = getDirentrySize(lname) + 1;
XPRINTF("Direntry size=%d\n", size);
*direntrySize = size;
//we search for sequence of deleted or empty entries (entry id = 0)
//1) search the tight slot (that fits completely. ex: size = 3, and slot space is 3 )
//2) search the suitable (loose) slot (ex: size = 3, slot space is 5)
slotStart = -1;
slotSize = 0;
tightIndex = -1;
looseIndex = -1;
cont = 1;
//search the entries for entry types
for (i = 0; i < entryCount && cont; i++) {
id = (entry[i] & 0x03);
if (id == 0) { //empty entry
if (slotStart >= 0) {
slotSize++;
} else {
slotStart = i;
slotSize = 1;
XPRINTF("*Start slot at index=%d ",slotStart);
}
} else { //occupied entry
#ifdef DEBUG
if (slotStart >=0) {
XPRINTF("End slot at index=%d slotSize=%d\n",i, slotSize);
}
#endif
if (tightIndex < 0 && slotSize == size) {
tightIndex = slotStart;
XPRINTF("!Set tight index= %d\n", tightIndex);
}
if (looseIndex < 0 && slotSize > size) {
looseIndex = slotStart + slotSize - size;
XPRINTF("!Set loose index= %d\n", looseIndex);
}
if (tightIndex >= 0 && looseIndex >= 0) {
cont = 0;
}
slotStart = -1;
slotSize = 0;
}
}
XPRINTF("\n");
// tight index - smaller fragmentation of space, the larger blocks
// are left for larger filenames.
// loose index - more fragmentation of direntry space, but the direntry
// name has space for future enlargement (of the name).
// i.e. no need to reposition the direntry and / or
// to allocate additional fat cluster for direntry space.
// we prefere tight slot if available, othervise we use the loose slot.
// if there are no tight and no loose slot then we position new direntry
// at the end of current direntry space
if (tightIndex >=0) {
return tightIndex;
}
if (looseIndex >=0) {
return looseIndex;
}
//last entry is (most likely) empty - use it
if ( (entry[entryCount-1]&0x03) == 0) {
return entryCount - 1;
}
return entryCount;
}
/*
scans current directory entries and fills the info records
lname - long filename (to test wether existing entry match the long name) (input)
sname - short filename ( dtto ^^ ) (input)
startCluster - valid start cluster of the directory or 0 if we scan the root directory (input)
record - info buffer (output)
maxRecord - size of the info buffer to avoid overflow
if file/directory already exist (return code 0) then:
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 fat_fillDirentryInfo(fat_bpb* bpb, unsigned char* lname, unsigned char* sname, char directory, unsigned int* startCluster, unsigned char* record, int maxRecord, unsigned int* retSector, int* retOffset) {
fat_direntry_sfn* dsfn;
fat_direntry_lfn* dlfn;
fat_direntry dir;
int i, j;
int dirSector;
unsigned int startSector;
unsigned int theSector;
int cont;
int ret;
int dirPos;
int clusterMod;
int seq;
cont = 1;
clusterMod = bpb->clusterSize - 1;
//clear name strings
dir.sname[0] = 0;
dir.name[0] = 0;
j = 0;
if (directory) directory = 0x10;
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 driver: read directory sector failed ! sector=%i\n", theSector);
return -EIO;
}
XPRINTF("read sector ok, scanning sector for direntries...\n");
//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;
// go through start of the sector till the end of sector
while (cont && dirPos < bpb->sectorSize && j< maxRecord) {
dsfn = (fat_direntry_sfn*) (sbuf + dirPos);
dlfn = (fat_direntry_lfn*) (sbuf + dirPos);
cont = fat_getDirentry(dsfn, dlfn, &dir); //get single directory entry from sector buffer
switch (cont) {
case 1: //short name
if (!(dir.attr & 0x08)) { //not volume label
//file we want to create already exist - return the cluster of the file
if ((strEqual(dir.sname, lname) == 0) || (strEqual(dir.name, lname) == 0) ) {
//found directory but requested is file (and vice veresa)
if ((dir.attr & 0x10) != directory) {
if (directory) return -ENOTDIR;
return -EISDIR;
}
XPRINTF("I: entry found! %s, %s = %s\n", dir.name, dir.sname, lname);
*retSector = theSector;
*retOffset = dirPos;
*startCluster = dir.cluster;
deSec[deIdx] = theSector;
deOfs[deIdx] = dirPos;
deIdx++;
return 0;
}
record[j] = 1;
seq = getShortNameSequence(dsfn->name, dsfn->ext, sname);
record[j] += ((seq & 0x3F) << 2);
if (seq > 63) { //we need to store seq number in the preceding record
if (j>0 && (record[j-1] & 0x03) == 2) {
record[j-1] += ((seq & 0x0FC0) >> 4);
} else {
return -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -