Writing to the FAT

25 Mar

Writing to the FAT
The FATwrite function accepts a pointer to a DISK structure (dsk), a cluster number (cls), and a value to write to the FAT entry for the cluster (v). The function gets the LBA of the sector containing the entry to write to, reads the sector into a buffer, writes the value to the entry, and writes the sector back to the storage media. The function calls the SectorRead and Sector- Write functions from Chapter 5.

The function uses the RAMwrite macro to write a value (d) to the address specified by a base address (a) plus an offset(f ):

#define RAMwrite(a, f, d) *(a + f) = d
word FATwrite(DISK *dsk, word cls, word v)
{
byte c;
byte i;
dword l
dword li;
word p;
byte q;
// Each entry is 2 bytes.
// To get the offset of the entry in the FAT, multiply the cluster number by 2.
p = cls * 2;
// To get the sector containing the entry, divide the entry’s offset by 512 .
l = dsk -> fat + (p >> 9 );
// To get the offset within the sector, set bits 9-16 of the entry’s offset to zero.
p &= 0×1ff;
// Read the sector into a buffer.
if ( SectorRead( l, dsk->buffer) != sdcValid)
return FAIL;

// Copy the passed value (v) into the FAT entry for the passed cluster number (cls)
// in the buffer. The LSB is at the lower offset.
RAMwrite(dsk -> buffer, p, v);
RAMwrite(dsk -> buffer, p+1, (v >> 8));
// Write the edited buffer to both FAT copies
for ( i = 0, li = l; i < dsk -> fatcopy; i++, li += dsk -> fatsize)
if ( SectorWrite(l, dsk -> buffer) != sdcValid)
return FAIL;
if (c >= LAST_CLUSTER_FAT16)
// The entry is an EOC marker.
c = LAST_CLUSTER;
return c;

Finding a File’s Next Cluster
The FILEget_next_cluster function can find the next cluster in a file. The function accepts a FILEOBJ pointer to a FILE structure (fo) and a number (n) that specifies how many clusters beyond the current cluster to look. The function sets the FILE structure’s ccls member to the requested cluster number. If n = 1, the function sets ccls to point to the cluster following the current cluster value in the passed file structure.

#define CE_GOOD 0 // No error.
#define CE_BAD_SECTOR_READ 7 // Error in reading a sector.
#define CE_FAT_EOF 60 // Attempt to read beyond the FAT’s EOF.
#define CE_INVALID_CLUSTER 9 // The cluster number > maxcls.
byte FILEget_next_cluster(FILEOBJ fo, word n)
{
word c;
word c2;
DISK *disk;
byte error = CE_GOOD;

// Save the FILE structure’s dsk member.
disk = fo -> dsk;
do {
// Save the file’s current cluster number.
c2 = fo -> ccls;
// Read the next cluster number from the FAT entry for the current cluster.
if ( (c = FATread(disk, c2)) == FAIL)
error = CE_BAD_SECTOR_READ;
else
{
if ( c >= disk -> maxcls)
{
// The cluster number is greater than the volume’s last cluster’s number.
// Set a return value but then check to see if the entry is an EOC marker.
error = CE_INVALID_CLUSTER;
}
c2 = LAST_CLUSTER;
if ( c >= c2)
{
// The entry is an EOC marker, so the current cluster is the file’s last one.
error = CE_FAT_EOF;
}
}
// The cluster number is valid. Store the new current cluster number.
fo -> ccls = c;
// Quit on finding the desired cluster or on error.
} while (–n > 0 && error == CE_GOOD);
return(error);
}

Performing Sequential Reads
The FATReadQueued function is identical to the FATread function above except that it’s optimized for doing multiple, sequential reads of the FAT. The function reads a sector from the media only if the entry to read is the first one in a sector. Otherwise, the function assumes that the passed DISK structure’s buffer member contains the sector with the entry to read.

word FATReadQueued( DISK *dsk, word ccls)
{
word c;
word d;
dword l;
word p;
byte q;
// Save the passed cluster number.
p = ccls;
// Each sector holds 256 two-byte entries.
// If the LSB of the cluster number = 0, the FAT entry is in a new sector.
if ((ccls & 0xFF) == 0×00)
{
// Get the sector number.
// The LBA of the FAT sector containing the cluster’s data is the FAT’s starting
// address plus the high byte of the current cluster’s address.
// (Each sector contains 256 two-byte entries.)
l = dsk -> fat + (p >> 8 );
// Read the sector containing the entry.
if (SectorRead( l, dsk -> buffer) != sdcValid)
return CLUSTER_FAIL;
}
// To find the number of the next cluster,
// read 2 bytes in the buffer of retrieved data
// beginning at offset = low byte of current cluster’s address << 1.
// Shift left 1 (multiply by 2) because each entry is 2 bytes.
c = RAMreadW( dsk -> buffer, ((p & 0xFF) << 1));
if (c >= LAST_CLUSTER_FAT16)
// The entry is an EOC marker.
c = LAST_CLUSTER;
return c;
}

Finding an Empty Cluster
To find an empty cluster in the FAT, firmware reads entries until finding an entry that contains 0000h.

The FATfindEmptyCluster function accepts a FILEOBJ pointer to a FILE structure and returns the number of an available cluster. The function starts looking at the cluster immediately following the file structure’s current cluster number (ccls). If ccls is the file’s final cluster and the function is looking for a cluster to append to the file, the new cluster will be the one following the current cluster if possible. The firmware thus avoids creating fragmented files when not required.

#define CLUSTER_EMPTY 0×0000
#define END_CLUSTER 0xFFFE
word FATfindEmptyCluster(FILEOBJ fo)
{
word c;
word curcls;
DISK *disk;
word value = 0×0;
// Save the DISK structure and current cluster number.
disk = fo -> dsk;
c = fo -> ccls;
// Cluster 2 is the first cluster.
if (c < 2)
c = 2;
curcls = c;
// Read the FAT entry for the current cluster.
FATread(disk, c);
// Starting at the cluster immediately following the current cluster number,
// scan through the FAT looking for an empty cluster.
while (c)
{
c++;
// If we get to the end of the FAT, start from the beginning.
if (value == END_CLUSTER || c >= disk -> maxcls)
c = 2;
// If we get to the current cluster, there are no empty entries.
if ( c == curcls)
{
c = 0;
break;
}
// Read an entry.
if ( (value = FATReadQueued(disk, c)) == CLUSTER_FAIL)
{
c = 0;
break;
}
// Quit the loop on finding an empty cluster.
if (value == CLUSTER_EMPTY)
break;
}
return(c);

Random Posts

No comments yet

Leave a Reply

You must be logged in to post a comment.