📄 fat_driver.c
字号:
/* * fat_driver.c - USB Mass storage driver for PS2 * * (C) 2004, Marek Olejnik (ole00@post.cz) * (C) 2004 Hermes (support for sector sizes from 512 to 4096 bytes) * (C) 2004 raipsu (fs_dopen, fs_dclose, fs_dread, fs_getstat implementation) * * FAT filesystem layer * * See the file LICENSE included with this distribution for licensing terms. *//* This layer should be "independent". Just supply a function that reads sectors from media (READ_SECTOR) and use fs_xxxx functions for file access. */#include <stdio.h>//#include <malloc.h>#include <sys/stat.h>#ifndef _PS2_#include <stdlib.h>#include <memory.h>#else#include <thbase.h>#define malloc(a) AllocSysMemory(0,(a), NULL)#define free(a) FreeSysMemory((a))#endif#include <errno.h>#include "scache.h"#include "fat_driver.h"#ifdef WRITE_SUPPORT#include "fat_write.h"#endif//#define DEBUG 1#include "mass_debug.h"// Added by Hermes extern unsigned Size_Sector; // store size of sector from usb mass#define MEMCPY(a,b,c) memcpy((a),(b),(c))#define SECTOR_SIZE Size_Sector //512 modified by Hermes#define DISK_INIT(a,b) scache_init((a), (b))#define DISK_CLOSE scache_close//#define READ_SECTOR(a, b) scache_readSector((a), (b))#define READ_SECTOR(a, b) scache_readSector((a), (void **)&b)#define FLUSH_SECTORS scache_flushSectors#define MAX_FILES 16fs_rec fsRec[MAX_FILES]; //file info recordfat_dir fsDir[MAX_FILES]; //directory entrystatic int fsCounter = 0;int mounted; //disk mounted=1 not monuted=0 fat_part partTable; //partition master recordfat_bpb partBpb; //partition bios parameter block// modified by Hermesunsigned char* sbuf; //sector bufferunsigned int cbuf[MAX_DIR_CLUSTER]; //cluster index buffer // 2048 by Hermesstatic int workPartition;unsigned int direntryCluster; //the directory cluster requested by getFirstDirentryint direntryIndex; //index of the directory childrenunsigned int lastChainCluster;int lastChainResult;int getI32(unsigned char* buf) { return (buf[0] + (buf[1] <<8) + (buf[2] << 16) + (buf[3] << 24));}int getI32_2(unsigned char* buf1, unsigned char* buf2) { return (buf1[0] + (buf1[1] <<8) + (buf2[0] << 16) + (buf2[1] << 24));}int getI16(unsigned char* buf) { return (buf[0] + (buf[1] <<8) );}int strEqual(unsigned char *s1, unsigned char* s2) { unsigned char u1, u2; for (;;) { u1 = *s1++; u2 = *s2++; if (u1 >64 && u1 < 91) u1+=32; if (u2 >64 && u2 < 91) u2+=32; if (u1 != u2) { return -1; } if (u1 == '\0') { return 0; } }}unsigned int fat_cluster2sector1216(fat_bpb* bpb, unsigned int cluster) { //return /* bpb->rootDirStart + (bpb->rootSize / 16) + (bpb->clusterSize * (cluster-2)); return bpb->rootDirStart + (bpb->rootSize / (bpb->sectorSize>>5))+ (bpb->clusterSize * (cluster-2)); //modified by Hermes ^ this work :)}unsigned int fat_cluster2sector32(fat_bpb* bpb, unsigned int cluster) { return bpb->rootDirStart + (bpb->clusterSize * (cluster-2));}unsigned int fat_cluster2sector(fat_bpb* bpb, unsigned int cluster) { switch(bpb->fatType) { case FAT32: return fat_cluster2sector32(bpb, cluster); default: return fat_cluster2sector1216(bpb, cluster); }}void fat_getPartitionRecord(part_raw_record* raw, part_record* rec) { rec->sid = raw->sid; rec->start = getI32(raw->startLBA); rec->count = getI32(raw->size);}/* 0x321, 0xABC byte| byte| byte| +--+--+--+--+--+--+ |2 |1 |C |3 |A |B | +--+--+--+--+--+--+*/unsigned int fat_getClusterRecord12(unsigned char* buf, int type) { if (type) { //1 return ((buf[1]<< 4) + (buf[0] >>4)); } else { // 0 return (((buf[1] & 0x0F) << 8) + buf[0]); }}// Get Cluster chain into <buf> buffer// returns:// 0 :if buf is full (bufSize entries) and more chain entries exist// 1-n :number of filled entries of the buf// -1 :error//for fat12 /* fat12 cluster records can overlap the edge of the sector so we need to detect and maintain these cases*/int fat_getClusterChain12(fat_bpb* bpb, unsigned int cluster, unsigned int* buf, int bufSize, int start) { int ret; int i; int recordOffset; int sectorSpan; int fatSector; int cont; int lastFatSector; unsigned char xbuf[4]; cont = 1; lastFatSector = -1; i = 0; if (start) { buf[i] = cluster; //strore first cluster i++; } while(i < bufSize && cont) { recordOffset = (cluster * 3) / 2; //offset of the cluster record (in bytes) from the FAT start fatSector = recordOffset / bpb->sectorSize; sectorSpan = 0; if ((recordOffset % bpb->sectorSize) == (bpb->sectorSize - 1)) { sectorSpan = 1; } if (lastFatSector != fatSector || sectorSpan) { ret = READ_SECTOR(bpb->partStart + bpb->resSectors + fatSector, sbuf); if (ret < 0) { printf("FAT driver:Read fat12 sector failed! sector=%i! \n", bpb->partStart + bpb->resSectors + fatSector ); return -1; } lastFatSector = fatSector; if (sectorSpan) { xbuf[0] = sbuf[bpb->sectorSize - 2]; xbuf[1] = sbuf[bpb->sectorSize - 1]; ret = READ_SECTOR(bpb->partStart + bpb->resSectors + fatSector + 1, sbuf); if (ret < 0) { printf("FAT driver:Read fat12 sector failed sector=%i! \n", bpb->partStart + bpb->resSectors + fatSector + 1); return -1; } xbuf[2] = sbuf[0]; xbuf[3] = sbuf[1]; } } if (sectorSpan) { // use xbuf as source buffer cluster = fat_getClusterRecord12(xbuf + (recordOffset % bpb->sectorSize) - (bpb->sectorSize-2), cluster % 2); } else { // use sector buffer as source buffer cluster = fat_getClusterRecord12(sbuf + (recordOffset % bpb->sectorSize), cluster % 2); } if (cluster >= 0xFF8) { cont = 0; //continue = false } else { buf[i] = cluster; i++; } } if (cont) { return 0; } else { return i; }}//for fat16 int fat_getClusterChain16(fat_bpb* bpb, unsigned int cluster, unsigned int* buf, int bufSize, int start) { int ret; int i; int indexCount; int fatSector; int cont; int lastFatSector; cont = 1; indexCount = bpb->sectorSize / 2; //FAT16->2, FAT32->4 lastFatSector = -1; i = 0; if (start) { buf[i] = cluster; //strore first cluster i++; } while(i < bufSize && cont) { fatSector = cluster / indexCount; if (lastFatSector != fatSector) { ret = READ_SECTOR(bpb->partStart + bpb->resSectors + fatSector, sbuf); if (ret < 0) { printf("FAT driver:Read fat16 sector failed! sector=%i! \n", bpb->partStart + bpb->resSectors + fatSector ); return -1; } lastFatSector = fatSector; } cluster = getI16(sbuf + ((cluster % indexCount) * 2)); if (cluster >= 0xFFF8) { cont = 0; //continue = false } else { buf[i] = cluster; i++; } } if (cont) { return 0; } else { return i; }}//for fat32int fat_getClusterChain32(fat_bpb* bpb, unsigned int cluster, unsigned int* buf, int bufSize, int start) { int ret; int i; int indexCount; int fatSector; int cont; int lastFatSector; cont = 1; indexCount = bpb->sectorSize / 4; //FAT16->2, FAT32->4 lastFatSector = -1; i = 0; if (start) { buf[i] = cluster; //strore first cluster i++; } while(i < bufSize && cont) { fatSector = cluster / indexCount; if (lastFatSector != fatSector) { ret = READ_SECTOR(bpb->partStart + bpb->resSectors + fatSector, sbuf); if (ret < 0) { printf("FAT driver: Read fat32 sector failed sector=%i! \n", bpb->partStart + bpb->resSectors + fatSector ); return -1; } lastFatSector = fatSector; } cluster = getI32(sbuf + ((cluster % indexCount) * 4)); if ((cluster & 0xFFFFFFF) >= 0xFFFFFF8) { cont = 0; //continue = false } else { buf[i] = cluster & 0xFFFFFFF; i++; } } if (cont) { return 0; } else { return i; }}int fat_getClusterChain(fat_bpb* bpb, unsigned int cluster, unsigned int* buf, int bufSize, int start) { if (cluster == lastChainCluster) { return lastChainResult; } switch (bpb->fatType) { case FAT12: lastChainResult = fat_getClusterChain12(bpb, cluster, buf, bufSize, start); break; case FAT16: lastChainResult = fat_getClusterChain16(bpb, cluster, buf, bufSize, start); break; case FAT32: lastChainResult = fat_getClusterChain32(bpb, cluster, buf, bufSize, start); break; } lastChainCluster = cluster; return lastChainResult;}void fat_invalidateLastChainResult() { lastChainCluster = 0;}void fat_getPartitionTable(fat_part* part) { part_raw_record* part_raw; int i; int ret; workPartition = 0; ret = READ_SECTOR(0 , sbuf); //read sector 0 - Disk MBR if (ret < 0) { printf("FAT driver: Read sector 0 failed ! \n"); return; } /* read 4 partition records */ for (i= 0; i < 4; i++) { part_raw = (part_raw_record*) (sbuf + 0x01BE + (i* 16)); fat_getPartitionRecord(part_raw, &part->record[i]); if (part->record[i].sid == 6 || part->record[i].sid == 4 || part->record[i].sid == 1 ||// fat 16, fat 12 part->record[i].sid == 0x0B || part->record[i].sid == 0x0C) { // fat 32 workPartition = i; } }}void fat_determineFatType(fat_bpb* bpb) { int sector; int clusterCount; //get sector of cluster 0 sector = fat_cluster2sector(bpb, 0); //remove partition start sector to get BR+FAT+ROOT_DIR sector count sector -= bpb->partStart; sector = bpb->sectorCount - sector; clusterCount = sector / bpb->clusterSize; //printf("Data cluster count = %i \n", clusterCount); if (clusterCount < 4085) { bpb->fatType = FAT12; } else if (clusterCount < 65525) { bpb->fatType = FAT16; } else { bpb->fatType = FAT32; }}void fat_getPartitionBootSector(part_record* part_rec, fat_bpb* bpb) { fat_raw_bpb* bpb_raw; //fat16, fat12 fat32_raw_bpb* bpb32_raw; //fat32 int ret; ret = READ_SECTOR(part_rec->start, sbuf); //read partition boot sector (first sector on partition) if (ret < 0) { printf("FAT driver: Read partition boot sector failed sector=%i! \n", part_rec->start); return; } bpb_raw = (fat_raw_bpb*) sbuf; bpb32_raw = (fat32_raw_bpb*) sbuf; //set fat common properties bpb->sectorSize = getI16(bpb_raw->sectorSize); bpb->clusterSize = bpb_raw->clusterSize; bpb->resSectors = getI16(bpb_raw->resSectors); bpb->fatCount = bpb_raw->fatCount; bpb->rootSize = getI16(bpb_raw->rootSize); bpb->fatSize = getI16(bpb_raw->fatSize); bpb->trackSize = getI16(bpb_raw->trackSize); bpb->headCount = getI16(bpb_raw->headCount); bpb->hiddenCount = getI32(bpb_raw->hiddenCountL); bpb->sectorCount = getI16(bpb_raw->sectorCountO); if (bpb->sectorCount == 0) { bpb->sectorCount = getI32(bpb_raw->sectorCount); // large partition } bpb->partStart = part_rec->start; bpb->rootDirStart = part_rec->start + (bpb->fatCount * bpb->fatSize) + bpb->resSectors; for (ret = 0; ret < 8; ret++) { bpb->fatId[ret] = bpb_raw->fatId[ret]; } bpb->fatId[ret] = 0; bpb->rootDirCluster = 0; fat_determineFatType(bpb); //fat32 specific info if (bpb->fatType == FAT32 && bpb->fatSize == 0) { bpb->fatSize = getI32(bpb32_raw->fatSize32); bpb->activeFat = getI16(bpb32_raw->fatStatus); if (bpb->activeFat & 0x80) { //fat not synced bpb->activeFat = (bpb->activeFat & 0xF); } else { bpb->activeFat = 0; } bpb->rootDirStart = part_rec->start + (bpb->fatCount * bpb->fatSize) + bpb->resSectors; bpb->rootDirCluster = getI32(bpb32_raw->rootDirCluster); for (ret = 0; ret < 8; ret++) { bpb->fatId[ret] = bpb32_raw->fatId[ret]; } bpb->fatId[ret] = 0; }}/* returns: 0 - no more dir entries 1 - short name dir entry found 2 - long name dir entry found 3 - deleted dir entry found*/int fat_getDirentry(fat_direntry_sfn* dsfn, fat_direntry_lfn* dlfn, fat_direntry* dir ) { int i, j; int offset; int cont; //detect last entry - all zeros if (dsfn->name[0] == 0 && dsfn->name[1] == 0) { return 0; } //detect deleted entry - it will be ignored if (dsfn->name[0] == 0xE5) { return 3; } //detect long filename if (dlfn->rshv == 0x0F && dlfn->reserved1 == 0x00 && dlfn->reserved2[0] == 0x00) { //long filename - almost whole direntry is unicode string - extract it offset = dlfn->entrySeq & 0x3f; offset--; offset = offset * 13; //name - 1st part cont = 1; for (i = 0; i < 10 && cont; i+=2) { if (dlfn->name1[i]==0 && dlfn->name1[i+1] == 0) { dir->name[offset] = 0; //terminate cont = 0; //stop } else { dir->name[offset] = dlfn->name1[i]; offset++; } } //name - 2nd part for (i = 0; i < 12 && cont; i+=2) { if (dlfn->name2[i]==0 && dlfn->name2[i+1] == 0) { dir->name[offset] = 0; //terminate cont = 0; //stop } else { dir->name[offset] = dlfn->name2[i]; offset++; } } //name - 3rd part for (i = 0; i < 4 && cont; i+=2) { if (dlfn->name3[i]==0 && dlfn->name3[i+1] == 0) { dir->name[offset] = 0; //terminate cont = 0; //stop } else { dir->name[offset] = dlfn->name3[i]; offset++; } } if ((dlfn->entrySeq & 0x40)) { //terminate string flag dir->name[offset] = 0; } return 2; } else { //short filename //copy name for (i = 0; i < 8 && dsfn->name[i]!= 32; i++) { dir->sname[i] = dsfn->name[i]; // NT梊栺椞堟撉傒庢傝 if (dsfn->reservedNT & 0x08 && dir->sname[i] >= 'A' && dir->sname[i] <= 'Z') { dir->sname[i] += 0x20; } } for (j=0; j < 3 && dsfn->ext[j] != 32; j++) { if (j == 0) { dir->sname[i] = '.'; i++; } dir->sname[i+j] = dsfn->ext[j]; // NT梊栺椞堟撉傒庢傝 if (dsfn->reservedNT & 0x10 && dir->sname[i+j] >= 'A' && dir->sname[i+j] <= 'Z') { dir->sname[i+j] += 0x20; } } dir->sname[i+j] = 0; //terminate if (dir->name[0] == 0) { //long name desn't exit for (i =0 ; dir->sname[i] !=0; i++) dir->name[i] = dir->sname[i]; dir->name[i] = 0; } dir->attr = dsfn->attr; dir->size = getI32(dsfn->size); dir->cluster = getI32_2(dsfn->clusterL, dsfn->clusterH); return 1; }}//Set chain info (cluster/offset) cachevoid fat_setFatDirChain(fat_bpb* bpb, fat_dir* fatDir) { int i,j; int index; int chainSize; int nextChain; int clusterChainStart ; unsigned int fileCluster; int fileSize; int blockSize; XPRINTF("FAT driver: reading cluster chain \n"); fileCluster = fatDir->chain[0].cluster; if (fileCluster < 2) { XPRINTF(" early exit... \n"); return; } fileSize = fatDir->size; blockSize = fileSize / DIR_CHAIN_SIZE; nextChain = 1; clusterChainStart = 0; j = 1; fileSize = 0; index = 0; while (nextChain) { chainSize = fat_getClusterChain(bpb, fileCluster, cbuf, MAX_DIR_CLUSTER, 1); if (chainSize == 0) { //the chain is full, but more chain parts exist chainSize = MAX_DIR_CLUSTER; fileCluster = cbuf[MAX_DIR_CLUSTER - 1]; }else { //chain fits in the chain buffer completely - no next chain exist nextChain = 0; }#ifdef DEBUG fat_dumpClusterChain(cbuf, chainSize, 0);#endif //process the cluster chain (cbuf) for (i = clusterChainStart; i < chainSize; i++) { fileSize += (bpb->clusterSize * bpb->sectorSize); while (fileSize >= (j * blockSize) && j < DIR_CHAIN_SIZE) { fatDir->chain[j].cluster = cbuf[i]; fatDir->chain[j].index = index; j++; } index++; } clusterChainStart = 1; } fatDir->lastCluster = cbuf[i-1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -