📄 fatvol.cpp
字号:
/*
* Copyright (C) 2004, Thejesh AP. All rights reserved.
*/
#include <sys\types.h>
#include <null.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <mm\new.h>
#include <drivers\drvreq.h>
#include <drivers\console.h>
#include <drivers\keyboard.h>
#include <fs\devmgr.h>
#include <mm\heap.h>
#include <fs\fatbuffer.h>
#include <fs\fatvol.h>
extern heap _heap_obj;
//#define __FATVOLUME_DEBUG
#define NUM_ENTRIES ((_bpb.spc * _bpb.bps) / sizeof(fdir))
#define CLUSTER_SZ (_bpb.spc * _bpb.bps)
#define FSOC(N) (((N - 2) * _bpb.spc) + fds)
#define LLE 0x40
fdir FATvolume::root = {0,0,0,0,0,0,0,0,0,0,0,0};
fdir FATvolume::pwd = {0,0,0,0,0,0,0,0,0,0,0,0};
fdir FATvolume::ppwd = {0,0,0,0,0,0,0,0,0,0,0,0};
uint FATvolume::totsz = 0;
fatbuffer FATvolume::_fb;
extern device_manager _dev_mgr;
int gnflag = 0;
FATvolume::FATvolume()
{
}
FATvolume::~FATvolume()
{
if(mounted) mounted = FALSE;
}
void FATvolume::init_volume(uint start,uint end,char drv,int slt_nr,int dv_nr)
{
mounted = FALSE;
drive = drv;
_pi.start_sec = start;
_pi.end_sec = end;
slot = slt_nr;
dev = dv_nr;
disk_req req;
byte buf[512];
_CR(req,DISK_READ,dev,start,1,buf);
if(_dev_mgr.driver_tab[slot].main(&req) < 0) return;
strncpy((char*)_bpb.OEMname,(char*)&buf[3],8);
_bpb.bps = *(ushort*)&buf[11];
_bpb.spc = buf[13];
_bpb.rsc = *(ushort*)&buf[14];
_bpb.numFATs = buf[16];
_bpb.rec = *(ushort*)&buf[17];
_bpb.totsec16 = *(ushort*)&buf[19];
_bpb.media = buf[21];
_bpb.FATsz16 = *(ushort*)&buf[22];
_bpb.spt = *(ushort*)&buf[24];
_bpb.numheads = *(ushort*)&buf[26];
_bpb.totsec32 = *(uint*)&buf[32];
_bpb.FATsz32 = *(uint*)&buf[36];
#ifdef __FATVOLUME_DEBUG
cout<<"OEM name :";
for(int i=0;i<8;i++)
cout<<(char)_bpb.OEMname[i];
cout<<endl;
cout<<"Bytes per sec :"<<_bpb.bps<<endl;
cout<<"Sec per clus :"<<(int)_bpb.spc<<endl;
cout<<"Res sec cnt :"<<_bpb.rsc<<endl;
cout<<"Num FATs :"<<(int)_bpb.numFATs<<endl;
cout<<"Root ent cnt :"<<_bpb.rec<<endl;
cout<<"Total sec16 :"<<_bpb.totsec16<<endl;
cout<<"Media ID :"<<(int)_bpb.media<<endl;
cout<<"FAT sz16 :"<<_bpb.FATsz16<<endl;
cout<<"Sec per track :"<<_bpb.spt<<endl;
cout<<"Num heads :"<<_bpb.numheads<<endl;
cout<<"Tot sec32 :"<<_bpb.totsec32<<endl;
cout<<"FAT sz32 :"<<_bpb.FATsz32<<endl;
#endif
if(is_FAT())
{
mounted = TRUE;
rds = ((_bpb.rec * 32) + (_bpb.bps - 1)) / _bpb.bps;
FATstart = _bpb.rsc;
FATsz = (_bpb.FATsz16) ? _bpb.FATsz16 : _bpb.FATsz32;
fds = _bpb.rsc + (_bpb.numFATs * FATsz) + rds;
totsec = (_bpb.totsec16) ? _bpb.totsec16 : _bpb.totsec32;
datasec = totsec - (_bpb.rsc + (_bpb.numFATs * FATsz) + rds);
coc = datasec / _bpb.spc;
if(coc < 4085) FATtype = FAT12;
else if(coc < 65525) FATtype = FAT16;
else FATtype = FAT32;
/* only for testing delete me*/
FATtype = FAT32;
totsz += FATsz * _bpb.bps;
#ifdef __FATVOLUME_DEBUG
cout<<"Root dir secs :"<<rds<<endl;
cout<<"FAT start :"<<FATstart<<endl;
cout<<"FATsz in sec :"<<FATsz<<endl;
cout<<"First data sec:"<<fds<<endl;
cout<<"Total sec :"<<totsec<<endl;
cout<<"Data sec :"<<datasec<<endl;
cout<<"Count of clus :"<<coc<<endl;
cout<<"FAT type :"<<FATtype<<endl;
#endif
}
}
int FATvolume::is_FAT()
{
/* This is wrong. the condition should be changed */
/* if(
(strncmp("MSWIN4.1",(char*)_bpb.OEMname,8) == 0) ||
(strncmp("MSDOS5.0",(char*)_bpb.OEMname,8) == 0) ||
(strncmp("MKDOSFS",(char*)_bpb.OEMname,7) == 0)
)*/
return 1;
// return 0;
}
int FATvolume::mount()
{
if(mounted) return -1;
disk_req req;
byte buf[512];
_CR(req,DISK_READ,dev,_pi.start_sec,1,buf);
if(_dev_mgr.driver_tab[slot].main(&req) < 0) return -1;
_bpb = *(BPB*)buf;
if(is_FAT())
{
mounted = TRUE;
rds = ((_bpb.rec * 32) + (_bpb.bps - 1)) / _bpb.bps;
FATstart = _bpb.rsc;
FATsz = (_bpb.FATsz16) ? _bpb.FATsz16 : _bpb.FATsz32;
fds = _bpb.rsc + (_bpb.numFATs * FATsz) + rds;
totsec = (_bpb.totsec16) ? _bpb.totsec16 : _bpb.totsec32;
datasec = totsec - (_bpb.rsc + (_bpb.numFATs * FATsz) + rds);
coc = datasec / _bpb.spc;
if(coc < 4085) FATtype = FAT12;
else if(coc < 65525) FATtype = FAT16;
else FATtype = FAT32;
}
return 0;
}
int FATvolume::unmount()
{
if(!mounted) return -1;
mounted = FALSE;
return 0;
}
char* FATvolume::get_next_name(char* path,char* pname)
{
static int rf = 0;
if(rf)
{
rf=0;
return NULL;
}
int i = 0;
if(*path == '\\') path++;
while(*path && *path !='\\') pname[i++] = *path++;
pname[i] = '\0';
if(*path == '\0')
{
rf=1;
return path;
}
return ++path;
}
fdir* FATvolume::get_dir_entry(char *name,uint &n,uint &clus_nr,uint &index)
{
/* the search is always in pwd except */
fdir *dir = new fdir[NUM_ENTRIES];
char org[255];
char cname[255];
strcpy(org,name);
uint start,buf_size;
start = get_start_clus(&pwd);
int present = FALSE;
uint num;
clus_nr = 0;
uint i;
if(!(name = gen_basis_name(name))) return NULL;
strcpy(cname,name);
while((start = get_next_clus(start,clus_nr,dir))!=0xFFFFFFFF)
{
if(is_8_3(org))
{
for(i=0;i<NUM_ENTRIES;i++)
{
if(strncmp((char*)dir[i].dir_name,cname,11) == 0)
{
present = TRUE;
gnflag = 0;
goto success;
}
}
}
else
{
char *uni = (char*)get_unicode(name,num);
fldir *ldir = (fldir*)dir;
/* should be improved */
for(int i=num-1;i<NUM_ENTRIES;i++)
{
int ord = 1;
int k;
for(k=i;k>i-num;k--)
{
if(
(strncmp((char*)ldir[k].ldir_name1,uni,10) == 0) &&
(strncmp((char*)ldir[k].ldir_name2,uni+=10,12) == 0) &&
(strncmp((char*)ldir[k].ldir_name3,uni+=12,4) == 0) &&
(ldir[k].ldir_ord & ord == ord)
)
ord++;
}
if(ord == num+1 && (ldir[k+1].ldir_ord & LLE))
{
i++;
present = TRUE;
gnflag = 0;
goto success;
}
}
}
}
success:
if(!present)
{
/*
*the dir entry is not present & the start clus of parent dir is in
*'start' & the read_buffer is in 'dir','last_dir' contains the parent
*dir entry.
*/
return NULL;
}
if(!is_dot_dotdot(name))
n = (is_8_3(org)) ? 2 : num + 1;
else
n = 1;
index = i;
return dir;
}
int FATvolume::put_dir_entry(char *name,byte attr,uint fsize)
{
if(!mounted) return -1;
uint t1,t2,t3;
if(get_dir_entry(name,t1,t2,t3)) return -1;
uint start = get_start_clus(&pwd);
int nfe = get_nfe(name);
fdir *dir = new fdir[NUM_ENTRIES];
uint clus_nr = 0;
while((start = get_next_clus(start,clus_nr,dir))!=0xFFFFFFFF)
{
int flag = 0;
/* should be improved */
int i;
for(i=0;i<(NUM_ENTRIES-nfe)+1;i++)
{
if(dir[i].dir_name[0] = 0x00)
{
flag = 1;
break;
}
for(int j=i;j<i+nfe;j++)
flag = (dir[j].dir_name[0] == 0xE5) ? 1 : 0;
if(flag) break;
}
if(flag)
{
/* dir[i]..dir[i+nfe-1] is avaiable*/
if(creat_dir_entry(name,dir,i,nfe,attr,fsize) < 0)
{
delete dir;
return -1;
}
if(write_clus(clus_nr,dir) < 0)
{
delete dir;
return -1;
}
return 0;
}
}
if(start == -1)
{
delete dir;
return -1;
}
/* No room in cluster chain, so expand cluster chain.last_clus = eoc in chain*/
uint new_clus;
if(!(new_clus = expand_clus(clus_nr)))
{
delete dir;
return -1;
}
memset(dir,0,NUM_ENTRIES*sizeof(fdir));
if(creat_dir_entry(name,dir,0,nfe,attr,fsize) < 0)
{
delete dir;
return -1;
}
if(write_clus(new_clus,dir) < 0)
{
delete dir;
return -1;
}
return 0;
}
int FATvolume::creat_dir_entry(char *name,fdir *dir,uint start,uint nfe,byte attr,uint fsize)
{
int b = start+nfe-1;
uint num;
char *uni = (char*)get_unicode(name,num);
if(!(name = gen_basis_name(name))) return -1;
if(!is_8_3(name))
if(!(name = gen_tail(name))) return -1;
strncpy((char*)dir[b].dir_name,name,11);
dir[b].dir_attr = attr;
dir[b].dir_NTres = 0;
dir[b].crt_time_tenth = 0;
dir[b].dir_crt_time = get_FAT_time();
dir[b].dir_crt_date = get_FAT_date();
dir[b].dir_lst_acc_date = dir[b].dir_crt_date;
uint fc = alloc_first_clus(name,attr);
dir[b].dir_fst_clusHI = (fc>>16)&0xFFFF;
dir[b].dir_wrt_time = dir[b].dir_crt_time;
dir[b].dir_wrt_date = dir[b].dir_crt_date;
dir[b].dir_fst_clusLO = fc & 0xFFFF;
dir[b].dir_file_size = fsize;
b--;
uint ord = 1;
fldir *ldir;
while(b >= start)
{
ldir = (fldir*)&dir[b];
ldir->ldir_ord = ord;
strncpy((char*)ldir->ldir_name1,uni,10);
ldir->ldir_attr = ATTR_LONG_NAME;
ldir->ldir_type = 0;
ldir->ldir_chksum = chksum(name);
strncpy((char*)ldir->ldir_name2,uni+=10,12);
ldir->ldir_fst_clusLO = 0;
strncpy((char*)ldir->ldir_name3,uni+=12,4);
b--;
ord++;
}
if(!is_dot_dotdot(name))
{
ldir->ldir_ord = ldir->ldir_ord | LLE;
if(fc) write_clus(fc,NULL);
}
return 0;
}
byte FATvolume::chksum(char *name)
{
short len;
byte sum = 0;
for(len=11;len!=0;len--)
{
sum = ((sum & 1) ? 0x80 : 0) + (sum>>1) + *name++;
}
return sum;
}
int FATvolume::del_dir_entry(char *name)
{
/*
*if name is a filename, simply delete the entry. if name is a dirname check if the dir
*is empty or not.if it is empty then delete it. if possible contract the cluster chain.
*/
fdir *dir;
uint n,clus_nr,index;
if(!(dir = get_dir_entry(name,n,clus_nr,index))) return -1;
/*
*dir[index]...dir[(index-n)+1] contain dir entry
*dir[index] = short dir entry,
*dir[index-1]...dir[(index-n)+1] = long dir entry
*clus_nr = clus_nr where this entry is found
*/
if(is_directory(dir[index]))
{
if(!is_empty(dir[index]))
{
delete dir;
return -1;
}
if( write_clus(get_start_clus(&dir[index]),NULL) < 0)
{
delete dir;
return -1;
}
}
byte flag = 0;
if(index+1 == NUM_ENTRIES || dir[index+1].dir_name[0] == 0x00)
flag = 1;
for(int i=index;i>=n-index-1;i--)
dir[i].dir_name[0] = (flag) ? 0x00 : 0xE5;
if((n-index)-1 == 0)
{
if(dir[index+1].dir_name[0] = 0x00)
{
if(!contract_clus(clus_nr))
{
delete dir;
return -1;
}
}
}
if(write_clus(clus_nr,dir) < 0)
{
delete dir;
return -1;
}
delete dir;
return 0;
}
void* FATvolume::read_file(char *name,uint &size)
{
fdir *dir;
uint n,clus_nr,index;
uint start;
if(!strcmp(name,".") && is_equal(pwd,root))
{
start = get_start_clus(&pwd);
}
else
{
if(!(dir = get_dir_entry(name,n,clus_nr,index)))
{
delete dir;
return NULL;
}
start = get_start_clus(&dir[index]);
}
void *buf;
if(!(buf = read_clus_chain(start,size)))
{
delete dir;
return NULL;
}
delete dir;
return buf;
}
int FATvolume::write_file(char *name,void *buf,uint size)
{
fdir *dir;
uint n,clus_nr,index;
uint start;
if(!strcmp(name,".") && is_equal(pwd,root))
{
cout<<". & root\n";
start = get_start_clus(&pwd);
}
else
{
if(!(dir = get_dir_entry(name,n,clus_nr,index)))
{
delete dir;
return -1;
}
start = get_start_clus(&dir[index]);
}
if(write_clus_chain(start,buf,size) < 0)
{
delete dir;
return -1;
}
delete dir;
return 0;
}
int FATvolume::delete_file(char *name)
{
fdir *dir;
uint n,clus_nr,index;
if(!(dir = get_dir_entry(name,n,clus_nr,index)))
{
delete dir;
return -1;
}
uint start = get_start_clus(&dir[index]);
if(free_clus_chain(start) < 0) {delete dir;return -1;}
/*free the directory entry in pwd*/
if(del_dir_entry(name) < 0) return -1;
delete dir;
return 0;
}
int FATvolume::get_short_dir_entry(char *name,fdir &d)
{
int __ret = -1;
fdir *dir;
uint n,clus_nr,index;
if(dir = get_dir_entry(name,n,clus_nr,index))
{
d = dir[index];
delete dir;
__ret = 0;
}
return __ret;
}
char* FATvolume::strip(char *name)
{
char *temp = new char[strlen(name)+1];
strcpy(temp,name);
strrev(temp);
int i=0,f=0;
while(*temp)
{
if(*temp != ' ')
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -