📄 fat.c
字号:
#include "fat.h"
#include "part.h"
/*
* Convert a string to lowercase.
*/
static void downcase(char *str)
{
while (*str != '\0')
{
TOLOWER(*str);
str++;
}
}
static block_dev_desc_t *cur_dev = NULL;
static unsigned long part_offset = 0;
static int cur_part = 1;
#define DOS_PART_TBL_OFFSET 0x1be
#define DOS_PART_MAGIC_OFFSET 0x1fe
#define DOS_FS_TYPE_OFFSET 0x36
int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr)
{
startblock += part_offset;
if (cur_dev == NULL)
return -1;
if (cur_dev->block_read)
{
//return cur_dev->block_read (cur_dev->dev, startblock, getsize, (unsigned long *)bufptr);
//add by wqh for debug
int i,ret;
ret=cur_dev->block_read (cur_dev->dev, startblock, getsize, (unsigned long *)bufptr);
//s_UartPrint("block_read(%d+%d %d)\n",startblock,part_offset,getsize);
//for(i=0;i<getsize*512;i++)
// s_UartPrint("[%05d] : %02x\n",i,bufptr[i]);
return ret;
}
return -1;
}
int
fat_register_device(block_dev_desc_t *dev_desc, int part_no)
{
unsigned char buffer[SECTOR_SIZE];
int i,j;
if (!dev_desc->block_read)
return -1;
cur_dev=dev_desc;
/* check if we have a MBR (on floppies we have only a PBR) */
if (dev_desc->block_read (dev_desc->dev, 0, 1, (ulong *) buffer) != 1)
{
FAT_DPRINT("** Can't read from device %d **\n", dev_desc->dev);
return -1;
}
//add by wqh for debug
FAT_DPRINT("** 11111:block_read (0, 1) **\n");
for(i=0;i<SECTOR_SIZE;i++)
{
if(i%0x10==0)
{
FAT_DPRINT("[%03x]: ",i);
//FAT_DPRINT("[%03x]:%02x ", i,buffer[i]);
}
FAT_DPRINT("%02x ",buffer[i]);
if((i+1)%0x10==0&&(i-0xf)>=0)
{
FAT_DPRINT(": ");
for(j=i-0xf;j<=i;j++)
{
if(buffer[j]=='\n')
FAT_DPRINT(" ");
else
FAT_DPRINT("%c ",buffer[j]);
}
FAT_DPRINT("\n");
}
}
/*
MBR(Main Boot Record),按其字面上的理解即为主引导记录区,位于整个硬盘
的0磁道0柱面1扇区。不过,在总共512字节的主引导扇区中,MBR只占用了其中的
446个字节(偏移0--偏移1BDH),另外的64个字节(偏移1BEH--偏移1FDH)交给
了DPT(Disk Partition Table硬盘分区表)(见下表),最后两个字节"55,AA"(
偏移1FEH- 偏移1FFH)是分区的结束标志。这个整体构成了硬盘的主引导扇区。
*/
if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa)
{
/* no signature found */
return -1;
}
//if(!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3))
//{
/* ok, we assume we are on a PBR only */
// cur_part = 1;
// part_offset=0;
// FAT_DPRINT("**1-partoffset=%d cur_part=%d**\n",part_offset,cur_part);
//}
//else
//{
//alter by simon 2009.10.21
//这样改的原因是,我发现,行的U盘都可以运行到这里,不行的,就不能运行到这
if(1)
{
disk_partition_t info;
if(!get_partition_info(dev_desc, part_no, &info))
{
part_offset = info.start;
cur_part = part_no;
FAT_DPRINT("**2-partoffset=%d cur_part=%d**\n",part_offset,cur_part);
}
else
{
FAT_DPRINT("** Partition %d not valid on device %d **\n",part_no,dev_desc->dev);
return -1;
}
}
return 0;
}
/*
* Get the first occurence of a directory delimiter ('/' or '\') in a string.
* Return index into string if found, -1 otherwise.
*/
static int
dirdelim(char *str)
{
char *start = str;
while (*str != '\0')
{
if (ISDIRDELIM(*str)) return str - start;
str++;
}
return -1;
}
/*
* Match volume_info fs_type strings.
* Return 0 on match, -1 otherwise.
*/
static int
compare_sign(char *str1, char *str2)
{
char *end = str1+SIGNLEN;
while (str1 != end)
{
if (*str1 != *str2)
{
return -1;
}
str1++;
str2++;
}
return 0;
}
/*
* Extract zero terminated short name from a directory entry.
*/
static void get_name (dir_entry *dirent, char *s_name)
{
char *ptr;
memcpy (s_name, dirent->name, 8);
s_name[8] = '\0';
ptr = s_name;
while (*ptr && *ptr != ' ')
ptr++;
if (dirent->ext[0] && dirent->ext[0] != ' ')
{
*ptr = '.';
ptr++;
memcpy (ptr, dirent->ext, 3);
ptr[3] = '\0';
while (*ptr && *ptr != ' ')
ptr++;
}
*ptr = '\0';
if (*s_name == DELETED_FLAG)
*s_name = '\0';
else if (*s_name == aRING)
*s_name = '?';
downcase (s_name);
}
/*
* Get the entry at index 'entry' in a FAT (12/16/32) table.
* On failure 0x00 is returned.
*/
static __u32
get_fatent(fsdata *mydata, __u32 entry)
{
__u32 bufnum;
__u32 offset;
__u32 ret = 0x00;
switch (mydata->fatsize)
{
case 32:
bufnum = entry / FAT32BUFSIZE;
offset = entry - bufnum * FAT32BUFSIZE;
break;
case 16:
bufnum = entry / FAT16BUFSIZE;
offset = entry - bufnum * FAT16BUFSIZE;
break;
case 12:
bufnum = entry / FAT12BUFSIZE;
offset = entry - bufnum * FAT12BUFSIZE;
break;
default:
/* Unsupported FAT size */
return ret;
}
/* Read a new block of FAT entries into the cache. */
if (bufnum != mydata->fatbufnum)
{
int getsize = FATBUFSIZE/FS_BLOCK_SIZE;
__u8 *bufptr = mydata->fatbuf;
__u32 fatlength = mydata->fatlength;
__u32 startblock = bufnum * FATBUFBLOCKS;
fatlength *= SECTOR_SIZE; /* We want it in bytes now */
startblock += mydata->fat_sect; /* Offset from start of disk */
if (getsize > fatlength) getsize = fatlength;
if (disk_read(startblock, getsize, bufptr) < 0)
{
FAT_DPRINT("Error reading FAT blocks\n");
return ret;
}
mydata->fatbufnum = bufnum;
}
/* Get the actual entry from the table */
switch (mydata->fatsize)
{
case 32:
ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]);
break;
case 16:
ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]);
break;
case 12:
{
__u32 off16 = (offset*3)/4;
__u16 val1, val2;
switch (offset & 0x3)
{
case 0:
ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
ret &= 0xfff;
break;
case 1:
val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
val1 &= 0xf000;
val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]);
val2 &= 0x00ff;
ret = (val2 << 4) | (val1 >> 12);
break;
case 2:
val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
val1 &= 0xff00;
val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]);
val2 &= 0x000f;
ret = (val2 << 8) | (val1 >> 8);
break;
case 3:
ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);;
ret = (ret & 0xfff0) >> 4;
break;
default:
break;
}
}
break;
}
FAT_DPRINT("ret: %d, offset: %d\n", ret, offset);
return ret;
}
/*
* Read at most 'size' bytes from the specified cluster into 'buffer'.
* Return 0 on success, -1 otherwise.
*/
static int
get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
{
int idx = 0;
__u32 startsect;
if (clustnum > 0)
{
startsect = mydata->data_begin + clustnum*mydata->clust_size;
}
else
{
startsect = mydata->rootdir_sect;
}
FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
if (disk_read(startsect, size/FS_BLOCK_SIZE , buffer) < 0)
{
FAT_DPRINT("Error reading data\n");
return -1;
}
if(size % FS_BLOCK_SIZE)
{
__u8 tmpbuf[FS_BLOCK_SIZE];
idx= size/FS_BLOCK_SIZE;
if (disk_read(startsect + idx, 1, tmpbuf) < 0)
{
FAT_DPRINT("Error reading data\n");
return -1;
}
buffer += idx*FS_BLOCK_SIZE;
memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE);
return 0;
}
return 0;
}
/*
* Read at most 'maxsize' bytes from the file associated with 'dentptr'
* into 'buffer'.
* Return the number of bytes read or -1 on fatal errors.
*/
static long
get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
unsigned long maxsize,unsigned long addr)
{
unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE;
__u32 curclust = START(dentptr);
__u32 endclust, newclust;
unsigned long actsize;
unsigned long addroffset=0;
__u8 tempbuffer[8*1024];
unsigned long newmaxsize,offset;
if(addr>=filesize) return 0;
if(!maxsize) return 0;
newmaxsize=addr+maxsize;
FAT_DPRINT("Filesize: %ld bytes\n", filesize);
if (newmaxsize > 0 && filesize > newmaxsize) filesize = newmaxsize;
FAT_DPRINT("Reading: %ld bytes\n", filesize);
actsize=bytesperclust;
endclust=curclust;
FAT_DPRINT("step1: actsize=%d endclust=%d \n",actsize,endclust);
do
{
/* search for consecutive clusters */
while(actsize < filesize)
{
FAT_DPRINT("step2: actsize=%d endclust=%d \n",actsize,endclust);
newclust = get_fatent(mydata, endclust);
if((newclust -1)!=endclust)
goto getit;
if (newclust <= 0x0001 || newclust >= 0xfff0)
{
FAT_DPRINT("curclust: 0x%x\n", newclust);
FAT_DPRINT("Invalid FAT entry\n");
return gotsize;
}
endclust=newclust;
actsize+= bytesperclust;
}
/* actsize >= file size */
actsize -= bytesperclust;
/* get remaining clusters */
if (get_cluster(mydata, curclust, tempbuffer, (int)actsize) != 0)
{
FAT_ERROR("Error reading cluster\n");
return -1;
}
FAT_DPRINT("step3: actsize=%d endclust=%d \n",actsize,endclust);
if((addroffset+actsize)>addr)
{
offset=0;
if(addr>addroffset) offset=addr-addroffset;
memcpy(buffer,tempbuffer+offset,actsize-offset);
gotsize += (int)(actsize-offset);
buffer+=actsize-offset;
}
addroffset+=actsize;
filesize -= actsize;
actsize= filesize;
/* get remaining bytes */
//gotsize += (int)actsize;
//filesize -= actsize;
//buffer += actsize;
//actsize= filesize;
if (get_cluster(mydata, endclust, tempbuffer, (int)actsize) != 0)
{
FAT_ERROR("Error reading cluster\n");
return -1;
}
FAT_DPRINT("step4: actsize=%d endclust=%d \n",actsize,endclust);
if((addroffset+actsize)>addr)
{
offset=0;
if(addr>addroffset) offset=addr-addroffset;
memcpy(buffer,tempbuffer+offset,actsize-offset);
gotsize += (int)(actsize-offset);
//buffer+=actsize-offset;
}
//addroffset+=actsize;
//filesize -= actsize;
//actsize= filesize;
//gotsize+=actsize;
return gotsize;
getit:
if (get_cluster(mydata, curclust, tempbuffer, (int)actsize) != 0)
{
FAT_ERROR("Error reading cluster\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -