// fat12.c // Author: Josh Holtrop // Created: 01/04/04 // Modified: 01/14/04 byte *fat12_readFile(char *fileName, DiskDevice *dd) { char *fileNameUCase = malloc(strlen(fileName) + 1); strcpy(fileNameUCase, fileName); ucase(fileNameUCase); dword iMadeClusterChain = getClusterChain(dd); Fat12Entry fe; if (fat12_getFileHandle(fileNameUCase, dd, &fe)) { free(fileNameUCase); if (iMadeClusterChain) { free(clusterChain); clusterChain = 0; } return 0; } byte *fp = (byte *)fat12_readClusterChain(dd, &fe); free(fileNameUCase); if (iMadeClusterChain) { free(clusterChain); clusterChain = 0; } return fp; } dword fat12_getFileHandle(char *fileName, DiskDevice *dd, Fat12Entry *destination) { if (strlen(fileName) < 1) return 1; if (fileName[strlen(fileName)-1] == '/') return 2; dword iMadeClusterChain = getClusterChain(dd); int fileName_length = strlen(fileName); int a; int entries = 1; for (a = 0; a < fileName_length; a++) { if (fileName[a] == '/') { fileName[a] = 0; entries++; } } char *pointer = fileName; Fat12Entry *workingDirectory = 0; Fat12Entry workingDir; for (a = 0; a < (entries - 1); a++) { if (fat12_getDirectoryHandle(pointer, dd, workingDirectory, &workingDir)) //an error occurred if this returns nonzero { if (iMadeClusterChain) { free(clusterChain); clusterChain = 0; } return 3; } workingDirectory = &workingDir; for (;;) //advance to the next dir name { pointer++; if (*pointer == 0) { pointer++; break; } } } if (fat12_getFileHandleInDirectory(pointer, dd, workingDirectory, destination)) //an error occurred if this returns nonzero { if (iMadeClusterChain) { free(clusterChain); clusterChain = 0; } return 4; } if (iMadeClusterChain) { free(clusterChain); clusterChain = 0; } return 0; } dword fat12_getFileHandleInDirectory(char *fileName, DiskDevice *dd, Fat12Entry *currDir, Fat12Entry *destination) { if (!currDir) // we are working in the root directory { Fat12Entry *rootDir = malloc(14*512); //root directory is 14 sectors long vfs_readSector(dd, 19, (byte *)rootDir, 14); int a; for (a = 0; a < 224; a++) //224 max root directory entries in 14 sectors { if (rootDir[a].fileName[0] == 0) break; if ((byte)rootDir[a].fileName[0] != 0xE5) { if ((rootDir[a].attributes & 0x18) == 0) //this entry is a directory { char dirName[9]; char dirExt[4]; memcpy(dirName, rootDir[a].fileName, 8); dirName[8] = 0; memcpy(dirExt, rootDir[a].ext, 3); dirExt[3] = 0; rtrim(dirName); rtrim(dirExt); char dirWhole[14]; strcpy(dirWhole, dirName); if (strlen(dirExt) > 0) //the directory has an extension { strcat(dirWhole, "."); strcat(dirWhole, dirExt); } if (strcmp(dirWhole, fileName)) //the entry found is a match { free(rootDir); *destination = rootDir[a]; return 0; } } } } free(rootDir); return 1; //no match found } dword retVal = 2; dword iMadeClusterChain = getClusterChain(dd); Fat12Entry *subDirectory = fat12_readClusterChain(dd, currDir); if (!subDirectory) return 5; dword numberOfClusters = fat12_readClusterChainCount(dd, currDir); int a; for (a = 0; a < (numberOfClusters * 16); a++) { if (subDirectory[a].fileName[0] == 0) break; if ((byte)subDirectory[a].fileName[0] != 0xE5) { if ((subDirectory[a].attributes & 0x18) == 0) //this entry is a directory { char dirName[9]; char dirExt[4]; memcpy(dirName, subDirectory[a].fileName, 8); dirName[8] = 0; memcpy(dirExt, subDirectory[a].ext, 3); dirExt[3] = 0; rtrim(dirName); rtrim(dirExt); char dirWhole[14]; strcpy(dirWhole, dirName); if (strlen(dirExt) > 0) //the directory has an extension { strcat(dirWhole, "."); strcat(dirWhole, dirExt); } if (strcmp(dirWhole, fileName)) //the entry found is a match { *destination = subDirectory[a]; retVal = 0; break; } } } } free(subDirectory); if (iMadeClusterChain) { free(clusterChain); clusterChain = 0; } return retVal; } dword fat12_getDirectoryHandle(char *directory, DiskDevice *dd, Fat12Entry *currDir, Fat12Entry *destination) { if (!currDir) // we are working in the root directory { Fat12Entry *rootDir = malloc(14*512); //root directory is 14 sectors long vfs_readSector(dd, 19, (byte *)rootDir, 14); int a; for (a = 0; a < 224; a++) //224 max root directory entries in 14 sectors { if (rootDir[a].fileName[0] == 0) break; if ((byte)rootDir[a].fileName[0] != 0xE5) { if ((rootDir[a].attributes & 0x18) == 0x10) //this entry is a directory { char dirName[9]; char dirExt[4]; memcpy(dirName, rootDir[a].fileName, 8); dirName[8] = 0; memcpy(dirExt, rootDir[a].ext, 3); dirExt[3] = 0; rtrim(dirName); rtrim(dirExt); char dirWhole[14]; strcpy(dirWhole, dirName); if (strlen(dirExt) > 0) //the directory has an extension { strcat(dirWhole, "."); strcat(dirWhole, dirExt); } if (strcmp(dirWhole, directory)) //the entry found is a match { free(rootDir); *destination = rootDir[a]; return 0; } } } } free(rootDir); return 1; //no match found } dword retVal = 2; dword iMadeClusterChain = getClusterChain(dd); Fat12Entry *subDirectory = fat12_readClusterChain(dd, currDir); if (!subDirectory) return 5; dword numberOfClusters = fat12_readClusterChainCount(dd, currDir); int a; for (a = 0; a < (numberOfClusters * 16); a++) { if (subDirectory[a].fileName[0] == 0) break; if ((byte)subDirectory[a].fileName[0] != 0xE5) { if ((subDirectory[a].attributes & 0x18) == 0x10) //this entry is a directory { char dirName[9]; char dirExt[4]; memcpy(dirName, subDirectory[a].fileName, 8); dirName[8] = 0; memcpy(dirExt, subDirectory[a].ext, 3); dirExt[3] = 0; rtrim(dirName); rtrim(dirExt); char dirWhole[14]; strcpy(dirWhole, dirName); if (strlen(dirExt) > 0) //the directory has an extension { strcat(dirWhole, "."); strcat(dirWhole, dirExt); } if (strcmp(dirWhole, directory)) //the entry found is a match { *destination = subDirectory[a]; retVal = 0; break; } } } } free(subDirectory); if (iMadeClusterChain) { free(clusterChain); clusterChain = 0; } return retVal; } Fat12Entry *fat12_readClusterChain(DiskDevice *dd, Fat12Entry *directory) { dword numberOfClusters = fat12_readClusterChainCount(dd, directory); if (numberOfClusters == 0) return 0; byte *bp = malloc(numberOfClusters * 512); Fat12Entry *retVal = (Fat12Entry *)bp; dword cluster = directory->firstCluster; while (cluster < 0xFF0) { vfs_readSector(dd, cluster + 31, bp, 1); cluster = fat12_getNextCluster(cluster); bp += 512; } return retVal; } dword fat12_readClusterChainCount(DiskDevice *dd, Fat12Entry *directory) { dword numberOfClusters = 0; dword cluster = directory->firstCluster; if (cluster == 0) return 0; while (cluster < 0xFF0) { cluster = fat12_getNextCluster(cluster); numberOfClusters++; } return numberOfClusters; } dword fat12_getNextCluster(dword thisCluster) { dword nextCluster = *(word *)((dword)clusterChain + ((thisCluster * 3) >> 1)); if (thisCluster & 0x01) //this is an odd cluster return nextCluster >> 4; else //this is an even cluster return nextCluster & 0x0FFF; } dword fat12_getFileSize(char *fileName, DiskDevice *dd) { Fat12Entry fe; if (fat12_getFileHandle(fileName, dd, &fe)) return 0xFFFFFFFF; return fe.fileSize; } dword getClusterChain(DiskDevice *dd) { if (!clusterChain) { clusterChain = malloc(9*512); //9 sectors for File Allocation Table (cluster chain) vfs_readSector(dd, 1, clusterChain, 9); //sectors 1 through 9 contain the first FAT return 1; //this call created the cluster chain } else return 0; //this call did not create the cluster chain }