Fat文件系统查找过程 查找一个文件是通过文件名查找的,对于fat文件系统,可以直接从vfatlookup函数看 主体流程如下:vfatlookupvfatfindfatsearchlongwhile(1)fatgetentry(inode,cpos,bh,de)fatnamematch(sbi,name,namelen,bufname,len)fatbuildinodeinodenewinode(sb);inodeiinoiunique(sb,MSDOSROOTINO);fatfillinode(inode,de) vfatlookup调了fatsearchlong查找文件,其中qnamename就是文件名,比如说我们打开file。txt,就会先查找文件,这里传入的参数qnamename就是文件名,打印出来就是file。txt。staticintvfatfind(structinodedir,conststructqstrqname,structfatslotinfosinfo){unsignedintlenvfatstriptaillen(qname);if(len0)returnENOENT;returnfatsearchlong(dir,qnamename,len,sinfo);} fatsearchlong里面有个死循环,里面先调用fatgetentry(inode,cpos,bh,de)获取目录项,也就是de变量,msdosdirentry这个结构体,这个就是fdt表,也是fat文件系统的目录项。 先判断文件名是否等于DELETEDFLAG,就是0xe5,如果是,代码这个是删除文件,直接continue获取下一个目录项继续解析。一般短文件名,通过fatnamematch(sbi,name,namelen,bufname,len)函数,匹配,匹配上的话,说明找到该文件,直接跳转到found,intfatsearchlong(structinodeinode,constunsignedcharname,intnamelen,structfatslotinfosinfo){structmsdossbinfosbiMSDOSSB(sb);structbufferheadbhNULL;wchartunicodeNULL;unsignedcharbufname〔FATMAXSHORTSIZE〕;lofftcpos0;interr,errENOENT;while(1){if(fatgetentry(inode,cpos,bh,de)1)parserecord:nrslots0;if(dename〔0〕DELETEDFLAG)if(deattr!ATTREXT(deattrATTRVOLUME))if(deattr!ATTREXTISFREE(dename))if(deattrATTREXT){intstatusfatparselong(inode,cpos,bh,de,unicode,nrslots);if(status0){}elseif(statusPARSEINVALID)elseif(statusPARSENOTLONGNAME)elseif(statusPARSEEOF)}Neverprepend。tohiddenfileshere。Thatisdoneonlyformsdosmounts(andonlywhendotsOKyes);ifweareexecutinghere,itisinthecontextofavfatmount。lenfatparseshort(sb,de,bufname,0);if(len0)Compareshortnameif(fatnamematch(sbi,name,namelen,bufname,len))if(nrslots){voidlongnameunicodeFATMAXUNICHARS;intsizePATHMAXFATMAXUNISIZE;Comparelongnamelenfatunitox8(sb,unicode,longname,size);if(fatnamematch(sbi,name,namelen,longname,len))}}found:includethedesinfoslotoffcposnrslotssizeof(de);sinfoiposfatmakeipos(sb,sinfobh,sinfode);err0;endofdir:if(unicode)putname(unicode);} 找到文件后,会调用fatbuildinode建立索引节点信息,因为索引节点不是一直存在的,在我们嵌入式场景中,内存通常比较小,内存回收的时候会释放掉之前建立过的索引节点,所以这里大部分情况下都是走newinode(sb)分配新的inode,然后调iunique(sb,MSDOSROOTINO)查找一个没使用过的编号填充到inodeiino,通过都是从1开始往后分配,inodeiino就像是身份证一样的信息,区别每个inode,这个我们调试一些文件系统问题的时候通常会用到它。structinodefatbuildinode(structsuperblocksb,structmsdosdirentryde,lofftipos){fatlockbuildinode(MSDOSSB(sb));inodefatiget(sb,ipos);if(inode)inodenewinode(sb);if(!inode){inodeERRPTR(ENOMEM);}inodeiinoiunique(sb,MSDOSROOTINO);inodeiversion1;errfatfillinode(inode,de);if(err){iput(inode);inodeERRPTR(err);}fatattach(inode,ipos);insertinodehash(inode);out:fatunlockbuildinode(MSDOSSB(sb));} 然后调用fatfillinode填充inode信息,可以看到第一个判断,如果这个目录项是目录,这里填充的一些信息,如: MSDOSI(inode)istartfatgetstart(sbi,de);就是获取簇号 MSDOSI(inode)ilogstartMSDOSI(inode) 其实就是簇号,可以参考创建目录时的处理,参考函数fatallocnewdir的实现。 setnlink的作用是设置inlink,它代表的是该目录的子目录数量,fatsubdirs就是计算子目录数量,一个目录至少有2个子目录,当前目录和上级目录。我的代码是4。14版本的,这里还加了个判断fatvalidatedir判断该目录是否为有效目录,据我所知,内核4。4版本是没有该函数判断的,这会导致一些问题不能及时发现。intfatfillinode(structinodeinode,structmsdosdirentryde){structmsdossbinfosbiMSDOSSB(inodeisb);MSDOSI(inode)ipos0;inodeiuidsbioptions。inodeigidsbioptions。inodeigenerationgetseconds();if((deattrATTRDIR)!ISFREE(dename)){inodeigeneration1;inodeimodefatmakemode(sbi,deattr,SIRWXUGO);MSDOSI(inode)istartfatgetstart(sbi,de);MSDOSI(inode)ilogstartMSDOSI(inode)errorfatcalcdirsize(inode);if(error0)MSDOSI(inode)setnlink(inode,fatsubdirs(inode));errorfatvalidatedir(inode);if(error0)}else{notadirectoryinodeigeneration1;inodeimodefatmakemode(sbi,deattr,((sbioptions。showexec!isexec(dename8))?SIRUGOSIWUGO:SIRWXUGO));MSDOSI(inode)istartfatgetstart(sbi,de);MSDOSI(inode)ilogstartMSDOSI(inode)inodeisizele32tocpu(desize);MSDOSI(inode)}if(deattrATTRSYS){if(sbioptions。sysimmutable)inodeiflagsSIMMUTABLE;}fatsaveattrs(inode,deattr);inodeiblocks((inodeisize(sbiclustersize1))((lofft)sbiclustersize1))9;fattimefat2unix(sbi,inodeimtime,detime,dedate,0);if(sbioptions。isvfat){fattimefat2unix(sbi,inodeictime,dectime,decdate,dectimecs);fattimefat2unix(sbi,inodeiatime,0,deadate,0);}return0;} 关于fat文件系统查找就介绍这几个函数,主要是要理解几个关键的结构体、inode,目录项这几个重要的东西在查找中的作用。fat文件系统删除 对于文件系统删除,有2个系统调用,入口函数一个是dounlinkat,一个是dormdir,它们大体流程一致,这里主要有2件事,一个是释放目录项,给fdt表文件名首字节设置成0xe5,那么查找的时候先判断dename〔0〕如果是DELETEDFLAG就跳过了,不记得可以往上看回查找过程,一个是释放簇(在fat表写为0),数据区不变。dounlinkatvfsunlinkdiriopunlinkvfatunlinkvfatfindfatremoveentrieswhile(nrslotsde(structmsdosdirentry)bhbdata){dename〔0〕DELETEDFLAG;删除标志0xe5}dputdentrykilldentrykilliputiputfinalevictopevictinodefatevictinode这里进入到fat文件系统层,往下就是释放簇fat文件系统创建目录 fatallocnewdir就是创建目录的函数,可以看到,创建的时候先在fat表找到一个未使用的簇号,分配出来,然后fatclustoblknr函数通过该簇号计算出扇区编号,然后用sbgetblk对应的扇区读到内存上,紧接着就是填充fdt表,de〔0〕就是当前目录,de〔1〕就是上级目录,还有就是填充一些其他信息,如修改时间,簇号等,fatzeroedcluster就是把该簇其他扇区数据清0。memcpy(de〔0〕。name,MSDOSDOT,MSDOSNAME);memcpy(de〔1〕。name,MSDOSDOTDOT,MSDOSNAME);intfatallocnewdir(structinodedir,structtimespects){structmsdossbinfosbiMSDOSSB(sb);structbufferheadbhs〔MAXBUFPERPAGE〕;le16date,u8interr,errfatallocclusters(dir,cluster,1);if(err)blknrfatclustoblknr(sbi,cluster);bhs〔0〕sbgetblk(sb,blknr);if(!bhs〔0〕){errENOMEM;}fattimeunix2fat(sbi,ts,time,date,timecs);de(structmsdosdirentry)bhs〔0〕fillingthenewdirectoryslots(。and。。entries)memcpy(de〔0〕。name,MSDOSDOT,MSDOSNAME);memcpy(de〔1〕。name,MSDOSDOTDOT,MSDOSNAME);deattrde〔1〕。attrATTRDIR;de〔0〕。lcasede〔1〕。lcase0;de〔0〕。timede〔1〕。de〔0〕。datede〔1〕。if(sbioptions。isvfat){extratimestampsde〔0〕。ctimede〔1〕。de〔0〕。ctimecsde〔1〕。de〔0〕。adatede〔0〕。cdatede〔1〕。adatede〔1〕。}else{de〔0〕。ctimede〔1〕。ctime0;de〔0〕。ctimecsde〔1〕。ctimecs0;de〔0〕。adatede〔0〕。cdatede〔1〕。adatede〔1〕。cdate0;}fatsetstart(de〔0〕,cluster);fatsetstart(de〔1〕,MSDOSI(dir)ilogstart);de〔0〕。sizede〔1〕。size0;memset(de2,0,sbsblocksize2sizeof(de));setbufferuptodate(bhs〔0〕);markbufferdirtyinode(bhs〔0〕,dir);errfatzeroedcluster(dir,blknr,1,bhs,MAXBUFPERPAGE);if(err)errorfree:fatfreeclusters(dir,cluster);error:}