色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

xv6的文件系統是如何實現的

Linux閱碼場 ? 來源:Rand ? 作者:Rand ? 2021-10-12 18:00 ? 次閱讀

文件系統

本文繼續來看 的文件系統部分, 將文件系統的設計分為 7 層: ,磁盤、緩存區、日志三個部分在前文已經說了,本文接著講述 ,目錄,路徑三個層次。

這部分的理論知識可以參考文章:捋一捋文件系統。本文直接來看 xv6 的文件系統這部分是如何實現的。

文件系統布局

再來系統的看看 xv6 文件系統的布局圖:

a8cd53e4-22a0-11ec-82a8-dac502259ad0.png

這個圖與 文檔給出的布局圖有些不一樣,主要是日志區的位置變化了。 文檔給出的布局圖日志區位于文件系統的末尾,但是根據源碼來看日志區應該是位于超級塊后面的。前文直接用的 文檔中的圖,應該是有誤的,實在抱歉。我看了幾個版本的 源碼和文檔,源碼是日志區都是安排在超級塊后面,而文檔的布局圖描述的是將日志區放在末尾。不過這不是重點,不影響咱們理解,不管位于哪兒,在超級塊中做相應修改就行。

引導塊、超級塊

第 0 塊是引導塊,里面存放的啟動程序也就是 ,詳見前文:實例講解多處理器下的計算機啟動

第 1 塊是超級塊,存有文件系統的元信息,相關結構體定義如下:

structsuperblock{
uintsize;//Sizeoffilesystemimage(blocks)文件系統大小,也就是一共多少塊
uintnblocks;//Numberofdatablocks數據塊數量
uintninodes;//Numberofinodes.//i結點數量
uintnlog;//Numberoflogblocks//日志塊數量
uintlogstart;//Blocknumberoffirstlogblock//第一個日志塊塊號
uintinodestart;//Blocknumberoffirstinodeblock//第一個i結點所在塊號
uintbmapstart;//Blocknumberoffirstfreemapblock//第一個位圖塊塊號
};

可以看出超級塊實則就是文件系統布局的信息集合。在 中我們可以知道:

#defineNINODES200
#defineMAXOPBLOCKS10
#defineLOGSIZE(MAXOPBLOCKS*3)
#defineFSSIZE1000
#defineIPB(BSIZE/sizeof(structdinode))


intnbitmap=FSSIZE/(BSIZE*8)+1;
intninodeblocks=NINODES/IPB+1;
intnlog=LOGSIZE;

intnmeta=2+nlog+ninodeblocks+nbitmap;
intnblocks=FSSIZE-nmeta;

intlogstart=2;
intinodestart=2+nlog;
intbmapstart=2+nlog+ninodeblocks;

從上述代碼可以看出,文件系統的各個部分從哪開始,到哪結束都是可以明確計算出來的,所以其實不管將日志區安排在哪,我們都可以從超級塊中獲取相應的位置大小信息。

數據區

緊接著超級塊的區域應該是 ,但是 的內容有些多有些復雜,我們放在后面講,先來看看數據區中數據塊的組織與管理。

數據塊的分配和釋放由位圖來管理,但位圖管理的區域不止數據區,而是整個文件系統。有關位圖的宏定義如下:

//Bitmapbitsperblock每個塊能有多少個bit
#defineBPB(BSIZE*8)
//Blockoffreemapcontainingbitforblockb塊b在哪個位圖塊上
#defineBBLOCK(b,sb)(b/BPB+sb.bmapstart)

分配回收

staticuintballoc(uintdev)
{
intb,bi,m;
structbuf*bp;

bp=0;
for(b=0;b//讀取位圖信息
for(bi=0;bi1<8);
if((bp->data[bi/8]&m)==0){//Isblockfree?如果該塊空閑
bp->data[bi/8]|=m;//Markblockinuse.標記該塊使用
log_write(bp);
brelse(bp);//釋放鎖
bzero(dev,b+bi);//將該塊置0
returnb+bi;//返回塊號
}
}
brelse(bp);//釋放鎖
}
panic("balloc:outofblocks");
}

staticvoidbfree(intdev,uintb)//釋放一個數據塊,相應位圖清零
{
structbuf*bp;
intbi,m;

bp=bread(dev,BBLOCK(b,sb));
bi=b%BPB;
m=1<8);
if((bp->data[bi/8]&m)==0)
panic("freeingfreeblock");
bp->data[bi/8]&=~m;
log_write(bp);
brelse(bp);
}

位圖塊中每一位都代表著一塊,該位置 1 表示相應的塊正在使用,該位置 0 表示相應的塊空閑。分配數據塊就是在位圖中尋找空閑位,然后將其置 1 就代表分配出去了。

上述代碼涉及的都是比較簡單的位運算,有詳細的注釋,就不說明了,釋放一個數據塊的操作就是分配的逆操作,也不再贅述。

inode

磁盤上的 dinode

緊接著超級塊后面的區域是 區域, 定義的 共有 200 個,每個磁盤上的 定義如下:

structdinode{
shorttype;//Filetype
shortmajor;//Majordevicenumber(T_DEVonly)
shortminor;//Minordevicenumber(T_DEVonly)
shortnlink;//Numberoflinkstoinodeinfilesystem
uintsize;//Sizeoffile(bytes)
uintaddrs[NDIRECT+1];//Datablockaddresses
};
#defineNDIRECT12

表示該 指向的文件的類型,在 里面就只有三種類型,普通文件,目錄文件,設備文

表示該文件的鏈接數,鏈接分為硬鏈接和軟連接,這里與鏈接數目直接相關的是硬鏈接,后面實現文件系統調用的時候我們會看到, 系統調用會創建一個新目錄項并且增加一個鏈接數。 系統調用將鏈接數減 1,如果該文件在內存中的引用數和鏈接數都為 0 的話,則會刪除該文件。這部分咱們后面再慢慢聊,本文只捎帶提一下。

表示文件的大小,這里是以字節為單位。

在 里面使用 和 來區分設備,同一類設備有著相同的 , 又表示該類設備中具體的某設備。后面我們會看到如果文件類型為設備,則讀寫的時候會根據 調用相應設備的讀寫程序。

每個 有 11 個一級指針,一個間接指針,用來指向數據塊。這些都是可以改變的, 有個關于支持大文件的實現就是要增加一個間接索引來實現。

inode 緩存

磁盤上的 在內存中也有相應的緩存:

struct{
structspinlocklock;
structinodeinode[NINODE];
}icache;//磁盤上i結點在內存中的緩存

內存中的 定義如下:

structinode{
uintdev;//Devicenumber設備號
uintinum;//Inodenumberinode號
intref;//Referencecount引用數
structsleeplocklock;//protectseverythingbelowhere
intvalid;//inodehasbeenreadfromdisk?是否有效

shorttype;//copyofdiskinode
shortmajor;
shortminor;
shortnlink;
uintsize;
uintaddrs[NDIRECT+1];
};

內存中的 比磁盤上的 多了幾個屬性,首先是設備號, 里面一切皆文件,設備也是文件,所以設備號來表示什么設備。但是 xv6 沒這么復雜,這里主要就是來區分磁盤的主盤和從盤。時為從盤, 時為主盤,這個值在讀寫磁盤的時候用到,用它來設置磁盤的 device 寄存器來指定主盤從盤。詳見:帶你了解磁盤驅動程序

表示引用數,這個要與 鏈接數作區別,目前可以暫且理解為 為磁盤上文件之間的關系,而 主要用于內存中引用該文件的次數,比如 關閉文件使引用數減 1。這部分在文件系統調用的時候再作詳細講解。

表示是否有效,跟磁盤那里緩存塊中的數據是否有效一個意思,如果緩存中的數據是從磁盤中讀取過來的,則有效。通常無效是因為 剛分配,所以里面的數據無效

整個 緩存區有一把自旋鎖,每個 緩存有把休眠鎖,為什么如此,道理還是同磁盤和緩存塊。首先它們都是公共資源,需要鎖來避免競爭條件。再者 的作用就是組織管理 ,像是一個分配器,訪問 的臨界區的時間是很短的,使用自旋鎖就行。而一個進程對某個 的使用時間可能很長,最好使用休眠鎖,其他進程也想要獲取該 的使用權時就休眠讓出 提高性能。

分配 inode

對于磁盤上的 , 并沒有什么組織管理結構,分配空閑 的方法就是簡單粗暴地從頭至尾循環查找空閑 。

structinode*
ialloc(uintdev,shorttype)
{
intinum;
structbuf*bp;
structdinode*dip;

for(inum=1;inum//讀取第inum個i結點所在的位置
dip=(structdinode*)bp->data+inum%IPB;//該i結點地址
if(dip->type==0){//afreeinode找到空閑i結點
memset(dip,0,sizeof(*dip));
dip->type=type;
log_write(bp);//markitallocatedonthedisk
brelse(bp);
returniget(dev,inum);//以內存中的i結點形式返回
}
brelse(bp);
}
panic("ialloc:noinodes");
}

#defineIBLOCK(i,sb)((i)/IPB+sb.inodestart)
#defineIPB(BSIZE/sizeof(structdinode))

先來看看下面兩個宏定義, 表示一個塊中能有幾個 , 表示第 個 在第幾塊。

分配數據塊的時候有位圖來組織管理,所以分配數據塊的時候就“從頭至尾”的查詢空閑位,而 沒有組織管理的機制,所以就直接從頭至尾的查詢 的使用情況。如果該 的 屬性為 0 表示該 空閑,可以分配,反之正是用當中不可分配。

分配了之后將該 初始化,將其數據全部置 0,然后賦其 屬性,表示該 指向一個 類型的文件。

分配了該 需要在磁盤上也將其標記為已分配,因為目前是在內存中操作的,得同步到磁盤上去,所以直接調用 將該 所在的緩存塊同步到磁盤。當然并未真正地直接寫到磁盤了,只是在將該緩存數據標記為臟,關于日志,讀寫磁盤的操作本文不贅述了,可以參考前文:如何實現一個簡單的日志系統

回到分配 的函數上來,磁盤上的 已分配,得到了 號,但是文件系統實際工作的時候使用的是內存中的 緩存,所以調用 來分配(獲取)一個內存中的 來緩存 數據:

staticstructinode*iget(uintdev,uintinum)
{
structinode*ip,*empty;

acquire(&icache.lock);

//Istheinodealreadycached?如果該dinode在內存中已緩存
empty=0;
for(ip=&icache.inode[0];ipif(ip->ref>0&&ip->dev==dev&&ip->inum==inum){//在緩存中找到該i結點
ip->ref++;//引用加1
release(&icache.lock);
returnip;
}
if(empty==0&&ip->ref==0)//Rememberemptyslot.記錄icache中空閑的inode
empty=ip;
}

//Recycleaninodecacheentry.
if(empty==0)
panic("iget:noinodes");
//該dinode在內存中沒有緩存,分配一個空閑inodeempty
//根據參數,初始化該空閑inode,還沒讀入數據,valid設為0
ip=empty;
ip->dev=dev;
ip->inum=inum;
ip->ref=1;
ip->valid=0;
release(&icache.lock);

returnip;
}

如果磁盤上的 在 中已有緩存,那么直接將該 的引用數加 1,再返回該 就行。如果沒有緩存則分配一個空閑的 ,根據參數初始化 ,因為沒有實際讀入 的數據,所以 的 屬性置 0 表示無效。

使用修改 inode

使用 之前需要加鎖:

voidilock(structinode*ip)
{
structbuf*bp;
structdinode*dip;

if(ip==0||ip->ref1)//空指針引用小于1都是錯誤的
panic("ilock");

acquiresleep(&ip->lock);//上鎖

if(ip->valid==0){//有效位為0,從磁盤讀入數據
bp=bread(ip->dev,IBLOCK(ip->inum,sb));
dip=(structdinode*)bp->data+ip->inum%IPB;
ip->type=dip->type;
ip->major=dip->major;
ip->minor=dip->minor;
ip->nlink=dip->nlink;
ip->size=dip->size;
memmove(ip->addrs,dip->addrs,sizeof(ip->addrs));
brelse(bp);
ip->valid=1;
if(ip->type==0)
panic("ilock:notype");
}
}

分配 的時候并未從磁盤中 讀入數據,只是將 的 置 0 表示數據無效,正式讀入 數據在這加鎖的時候進行。

對緩存中 的修改需要同步到磁盤上的 :

voidiupdate(structinode*ip)
{
structbuf*bp;
structdinode*dip;

bp=bread(ip->dev,IBLOCK(ip->inum,sb));//讀取磁盤上的i結點
dip=(structdinode*)bp->data+ip->inum%IPB;
dip->type=ip->type;//update
dip->major=ip->major;
dip->minor=ip->minor;
dip->nlink=ip->nlink;
dip->size=ip->size;
memmove(dip->addrs,ip->addrs,sizeof(ip->addrs));
log_write(bp);
brelse(bp);
}

用完 需要 “放下” 它:

voidiput(structinode*ip)
{
acquiresleep(&ip->lock);//取鎖
if(ip->valid&&ip->nlink==0){
//獲取該i結點的引用數
acquire(&icache.lock);
intr=ip->ref;
release(&icache.lock);

if(r==1){
//inodehasnolinksandnootherreferences:truncateandfree.
itrunc(ip);
ip->type=0;
iupdate(ip);
ip->valid=0;
}
}
releasesleep(&ip->lock);

acquire(&icache.lock);
ip->ref--;
release(&icache.lock);
}

該函數將 的引用數減 1,如果本身就是該 的最后一個引用,且鏈接數也為 0,那么調用 將該 指向的所有數據塊全部釋放,也就相當于刪除了 指向的文件

表示該 已釋放,被回收到了 。將 信息更新到磁盤上的 之后將 置 0 表數據不再有效。

索引

的索引部分用來指向數據塊

staticuintbmap(structinode*ip,uintbn)//給i結點第bn個索引指向的地方分配塊
{
uintaddr,*a;
structbuf*bp;

//bn為直接索引
if(bn//如果第bn個索引指向的塊還未分配,則分配,否則返回塊號
if((addr=ip->addrs[bn])==0)
ip->addrs[bn]=addr=balloc(ip->dev);
returnaddr;
}

bn-=NDIRECT;//bn為間接索引

if(bn//Loadindirectblock,allocatingifnecessary.
if((addr=ip->addrs[NDIRECT])==0)//如果間接索引所在的塊還未分配,分配
ip->addrs[NDIRECT]=addr=balloc(ip->dev);
bp=bread(ip->dev,addr);//讀取一級索引塊
a=(uint*)bp->data;
if((addr=a[bn])==0){//如果該索引指向的塊還未分配,分配
a[bn]=addr=balloc(ip->dev);
log_write(bp);
}
brelse(bp);
returnaddr;//返回索引bn指向的塊的塊號
}

panic("bmap:outofrange");
}

返回索引 指向的數據塊塊號,如果該數據塊未分配,則分配之后再返回該塊塊號。

staticvoiditrunc(structinode*ip)
{
inti,j;
structbuf*bp;
uint*a;

for(i=0;i//釋放直接索引指向的數據塊
if(ip->addrs[i]){
bfree(ip->dev,ip->addrs[i]);
ip->addrs[i]=0;
}
}

if(ip->addrs[NDIRECT]){
bp=bread(ip->dev,ip->addrs[NDIRECT]);//讀取一級索引塊
a=(uint*)bp->data;
for(j=0;j//釋放一級索引指向的塊
if(a[j])
bfree(ip->dev,a[j]);
}
brelse(bp);
bfree(ip->dev,ip->addrs[NDIRECT]);//釋放一級索引塊
ip->addrs[NDIRECT]=0;
}

ip->size=0;
iupdate(ip);
}

,截斷 ,不知怎樣翻譯,但這個函數的實際工作就是將 所指向的數據塊全部釋放,也就相當于刪除文件了。具體的工作方式就是一個個的判斷索引是否有效,如果有效就調用 釋放,然后將該索引置為無效。基本上就與 做相反的工作。

讀寫數據

intreadi(structinode*ip,char*dst,uintoff,uintn)//從inode讀取數據
{
uinttot,m;
structbuf*bp;

if(ip->type==T_DEV){//如果該inode指向的是設備文件
if(ip->major0||ip->major>=NDEV||!devsw[ip->major].read)
return-1;
returndevsw[ip->major].read(ip,dst,n);//使用設備特有的讀取方式
}

if(off>ip->size||off+n//如果開始讀取的位置超過文件末尾,如果讀取的字節數是負數
return-1;
if(off+n>ip->size)//如果從偏移量開始的n字節超過文件末尾
n=ip->size-off;//則只能夠再讀取這么多字節

for(tot=0;tot//tol:目前總共已讀的字節數,n:需要讀取的字節數,off:從這開始讀,dst:目的地
bp=bread(ip->dev,bmap(ip,off/BSIZE));//讀取off所在的數據塊到緩存塊
m=min(n-tot,BSIZE-off%BSIZE);//一次性最多讀取m字節
memmove(dst,bp->data+off%BSIZE,m);//賦值數據到dst
brelse(bp);//釋放緩存塊
}
returnn;
}

intwritei(structinode*ip,char*src,uintoff,uintn)
{
uinttot,m;
structbuf*bp;

if(ip->type==T_DEV){
if(ip->major0||ip->major>=NDEV||!devsw[ip->major].write)
return-1;
returndevsw[ip->major].write(ip,src,n);
}

if(off>ip->size||off+nreturn-1;
if(off+n>MAXFILE*BSIZE)
return-1;

for(tot=0;totdev,bmap(ip,off/BSIZE));
m=min(n-tot,BSIZE-off%BSIZE);
memmove(bp->data+off%BSIZE,src,m);
log_write(bp);
brelse(bp);
}

函數用來讀取數據,從 ip 指向的文件中,從 開始讀,讀取 字節到 中去。

如果 指向的文件類型是設備,那么讀取數據要使用專門的讀取方式,比如說控制臺有著自己專門的讀入數據方式,這些設備的讀取方法集合在 數組當中。關于這部分我們后面的文章再詳述,這里只說磁盤上的文件的讀寫。

緊接著判斷了一下參數的合理性,比如 不應超過文件末尾,讀取的字節數 不應該是負數,如果 超過了文件末尾,那么最多只能讀取 個字節數,要修改 的值。

文件數據可能有多塊, 表示 所在的塊數,這個塊數是相對于該文件開頭的塊號,調用 獲取 所在的絕對塊號。拿到 所在數據塊的絕對塊號之后調用 讀取該數據塊的數據到緩存塊 。

數據在內存中已經準備完畢,可以賦值移動數據了。但是每次讀取的數據有上限,不能超過 ,這是還需要讀取的字節數,不能超過 ,這是每次最多能夠讀取的字節數。不能超過這兩者,所以兩者之中取較小值。

,將數據源 中的數據寫 字節到 指向的文件中,從偏移量為 的地方開始寫。

基本上是與 相反的操作,只是最后需要更新 信息,因為像文件中寫數據,該文件會變大, 是文件的代表與文件一一對應,需要更新 的 size 屬性,然后再調用 將 同步到磁盤上的 。

目錄

目錄也是文件,只是它的數據有些特殊,其數據是一個個目錄項,其主要屬性有文件名, 編號。

是一個文件的代言人,一個文件與一個 一一對應,但是 的屬性里面并沒有文件名。文件名這個屬性在目錄項這指出,目錄項的主要作用就是將 和文件名聯系起來。

結構定義

structdirent{//目錄項結構
ushortinum;
charname[DIRSIZ];
};

#defineDIRSIZ14

中目錄項只由兩項組成,文件名和 編號。

查找目錄項

structinode*dirlookup(structinode*dp,char*name,uint*poff)
{
uintoff,inum;
structdirentde;

if(dp->type!=T_DIR)//如果該文件不是目錄文件
panic("dirlookupnotDIR");

for(off=0;offsize;off+=sizeof(de)){
if(readi(dp,(char*)&de,off,sizeof(de))!=sizeof(de))//讀取dp指向的目錄文件,每次讀一個目錄項
panic("dirlookupread");
if(de.inum==0)//如果是根目錄??????????????
continue;
if(namecmp(name,de.name)==0){//根據名字找文件
//entrymatchespathelement
if(poff)//記錄該目錄項在目錄中的偏移
*poff=off;
inum=de.inum;//name文件的inode編號
returniget(dp->dev,inum);//或取該inode
}
}

return0;
}

這個函數用來在 指向的目錄文件下尋找名為 的目錄項,將該目錄項的偏移量記錄在 中,最后返回名字為 的文件的 。

因此根據文件名查找文件的是指就是在目錄文件中查找目錄項的過程,具體的查找方式就是一個個的比對目錄項的名稱和要查找的文件名是否相同,如果相同,則找到,反之說明該目錄下并沒有要查找的文件

添加目錄項

intdirlink(structinode*dp,char*name,uintinum)
{
intoff;
structdirentde;
structinode*ip;

//Checkthatnameisnotpresent.
if((ip=dirlookup(dp,name,0))!=0){
iput(ip);//dirlookup調用iget使引用數加1,所以調用iput使引用數減1
return-1;//name目錄項已存在,返回-1
}

//Lookforanemptydirent.
for(off=0;offsize;off+=sizeof(de)){
if(readi(dp,(char*)&de,off,sizeof(de))!=sizeof(de))
panic("dirlinkread");
if(de.inum==0)//找到一個空閑目錄項
break;
}

strncpy(de.name,name,DIRSIZ);//設置目錄項的文件名字
de.inum=inum;//設置目錄項的i結點編號
if(writei(dp,(char*)&de,off,sizeof(de))!=sizeof(de))//將該目錄項寫進dp指向的目錄文件中
panic("dirlink");

return0;
}

此函數用來在 指向的目錄文件中添加一個目錄項,通常是創建了一個新文件,需要在該目錄下添加這個新文件的信息

首先查找該目錄項是否存在,如果不存在則找一個空閑目錄項位置,將新文件的 和文件名寫進去。

路徑

路徑,何為路徑,比如常見的 ,仔細觀察,會發現,路徑實則是一個個文件名組成的,這個文件可能是目錄文件,也可能是普通文件。一般最后一項是普通文件名,中間的都是目錄文件名

另外像 這種路徑以 '/' 開頭表示絕對路徑, 這種不以 '/' 開頭的表示相對路徑。這兩種路徑大家應該都很熟悉了,不再多做解釋,或者可以參考文章捋一捋文件系統,其中詳細的捋了捋文件系統的理論知識。

不論哪一種路徑表示,都需要一個路徑解析函數,將其中一個個文件名給提取出來:

staticchar*skipelem(char*path,char*name)
{
char*s;
intlen;

while(*path=='/')//跳過'/'
path++;
if(*path==0)//路徑空
return0;
s=path;
while(*path!='/'&&*path!=0)//path繼續向后移,剝出最前面的目錄名
path++;
len=path-s;//記錄該目錄名的長度
if(len>=DIRSIZ)
memmove(name,s,DIRSIZ);//將該目錄名復制給name
else{
memmove(name,s,len);
name[len]=0;
}
while(*path=='/')//繼續跳過'/'
path++;
returnpath;//返回剩下的路徑
}

調用一次解析一個頭部的文件名放在 中,返回剩下的路徑。

用源碼注釋中的例子來說明:

skipelem("a/bb/c",name)="bb/c",settingname="a"
skipelem("http:///a//bb",name)="bb",settingname="a"
skipelem("a",name)="",settingname="a"
skipelem("",name)=skipelem("http:////",name)=0
staticstructinode*
namex(char*path,intnameiparent,char*name)
{
structinode*ip,*next;

if(*path=='/')//絕對路徑
ip=iget(ROOTDEV,ROOTINO);//讀取根目錄
else//相對路徑
ip=idup(myproc()->cwd);//讀取當前工作目錄

while((path=skipelem(path,name))!=0){
ilock(ip);
if(ip->type!=T_DIR){
iunlockput(ip);
return0;
}
if(nameiparent&&*path==''){//如果是要返回父結點,并且剩下的路徑已經為空,則當前結點就是i結點直接返回
//Stoponelevelearly.
iunlock(ip);
returnip;
}
if((next=dirlookup(ip,name,0))==0){//查詢下一個目錄
iunlockput(ip);
return0;
}
iunlockput(ip);
ip=next;//當前目錄指向下一個,然后while循環,直到解析到最后
}
if(nameiparent){
iput(ip);
return0;
}
returnip;
}

這個函數根據路徑返回 ,比如說路徑 ,如果 有效,則返回文件 的 ,如果 無效,則返回文件 的 。

這個函數主要是對路徑解析函數 和查找目錄項函數 函數的運用,根據路徑查找文件的步驟大致如下:

  • 獲取當前目錄的
  • 根據 獲取目錄文件
  • 在該目錄文件下根據文件名查找文件/目錄
  • 循環上述過程直到文件被找到

函數就是上述過程的實現,至于這個函數的具體怎么實現的,就不詳細說明了,可以自己舉個例子根據代碼模擬一下過程就明白了。在模擬的過程中主要注意幾個條件判斷:

  • (path = skipelem(path, name)) != 0,當 為空字符串的才返回 0,也就是說 skipelem("", name) = 0。path 指向一個空字符串,并不是說 path 本身為空
  • if(nameiparent && *path == ''), 為空字符串的時候也就是 "" 的時候 *path = ''

另外如果是相對路徑的話,當前目錄需要從進程 中的 屬性中獲取,相關內容后面進程再詳述。

本文主要介紹了 文件系統 ,目錄,路徑三個層次的設計與實現,應該對這三個概念會有個更深刻的認識。 是文件的代表,與文件一一對應,目錄也是文件,只是其數據是其他文件的信息,也就是一個個目錄項。目錄項是其他文件的文件名和相應的 編號組合而成。而路徑呢?就是一個個文件名組合在一起的字符串。可以使用路徑解析函數將一個個文件名解析出來,然后根據一層層目錄中的目錄項從上至下地查找文件

好啦本文就到這里了,有什么錯誤還請批評指針,也歡迎大家來同我討論交流一起學習進步。

責任編輯:haq
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 文件
    +關注

    關注

    1

    文章

    565

    瀏覽量

    24727
  • 代碼
    +關注

    關注

    30

    文章

    4779

    瀏覽量

    68525

原文標題:inode、目錄、路徑

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    華納云:VFS在提升文件系統性能方面的具體實踐

    VFS(Virtual File System)通過提供統一的接口和抽象層,使得操作系統能夠以高效的方式管理和訪問不同的文件系統。以下是一些VFS在提升文件系統性能方面的具體實踐示例: 統一的
    的頭像 發表于 11-27 15:59 ?160次閱讀

    Linux根文件系統的掛載過程

    Linux根文件系統(rootfs)是Linux系統中所有其他文件系統和目錄的起點,它是內核啟動時掛載的第一個文件系統
    的頭像 發表于 10-05 16:50 ?403次閱讀

    如何構建Linux根文件系統

    構建Linux根文件系統是一個涉及多個步驟和概念的過程,它對于Linux系統的啟動和運行至關重要。
    的頭像 發表于 10-05 16:47 ?293次閱讀

    小型文件系統如何選擇?FatFs和LittleFs優缺點比較

    和刪除文件實現了數據的持久化存儲和分層次的目錄結構。文件系統的存在極大地簡化了數據管理任務,提升了系統整體的穩定性和便利性,對于系統配置、
    的頭像 發表于 09-29 16:14 ?1600次閱讀
    小型<b class='flag-5'>文件系統</b>如何選擇?FatFs和LittleFs優缺點比較

    想提高開發效率,不要忘記文件系統

    ?同學們都知道,開發過程中文件系統的重要性,同樣的,4G-Cat.1模組的文件系統也非常重要,它通常與數據傳輸速度、存儲效率,以及數據安全性等有非常重要的關系,在應用開發中也非常重要。
    的頭像 發表于 09-21 08:18 ?232次閱讀
    想提高開發效率,不要忘記<b class='flag-5'>文件系統</b>

    如何更改Linux文件系統終端顯示顏色

    自己制作的簡單 Linux 文件系統,你會發現終端顯示為黑白色,很不好看
    的頭像 發表于 08-12 17:29 ?527次閱讀
    如何更改Linux<b class='flag-5'>文件系統</b>終端顯示顏色

    如何修改buildroot和debian文件系統

    本文檔主要介紹在沒有編譯環境的情況下,如何修改buildroot和debian文件系統方法,如在buildroot文件系統中添加文件、修改目錄等文件操作,在debian
    的頭像 發表于 07-22 17:46 ?458次閱讀
    如何修改buildroot和debian<b class='flag-5'>文件系統</b>

    linux--sysfs文件系統

    sysfs文件系統 sysfs,全稱為System Filesystem,是一個由Linux內核實現的虛擬文件系統。它扮演著一個橋梁的角色,將內核中的設備和驅動程序信息以文件的形式呈現
    的頭像 發表于 07-08 11:37 ?844次閱讀
    linux--sysfs<b class='flag-5'>文件系統</b>

    VisionFive v1下移植xv6,運行到main.c時會出現莫名其妙錯誤為什么?

    不足,突破不了uart模式下加載32K的大小限制,偶然發現VisionFive v1下有更好方式加載運行xv6內核,依據“JH7100 Boot User Guide,Version: V1 Date
    發表于 05-21 08:15

    【嵌入式SD NAND】基于FATFS/Littlefs文件系統的日志框架實現

    文章目錄 【嵌入式】基于FATFS/Littlefs文件系統的日志框架實現 1. 概述 2. 設計概要 3. 設計實現 3.1 初始化 `init` 3.2 日志寫入 `write` 3.3 日志
    的頭像 發表于 03-14 18:13 ?1054次閱讀
    【嵌入式SD NAND】基于FATFS/Littlefs<b class='flag-5'>文件系統</b>的日志框架<b class='flag-5'>實現</b>

    【嵌入式SD NAND】基于FATFS/Littlefs文件系統的日志框架實現

    文章目錄【嵌入式】基于FATFS/Littlefs文件系統的日志框架實現1.概述2.設計概要3.設計實現3.1初始化`init`3.2日志寫入`write`3.3日志讀取`read`3.4注銷
    的頭像 發表于 03-14 18:12 ?1156次閱讀
    【嵌入式SD NAND】基于FATFS/Littlefs<b class='flag-5'>文件系統</b>的日志框架<b class='flag-5'>實現</b>

    STM32L552VET6配置SDMMCH和文件系統,加載文件系統掛載存儲卡會返回FR_NOT_READY如何解決?

    STM32L552VET6配置SDMMCH和文件系統,不加載文件系統可以正常操作存儲卡,但是加載文件系統掛載存儲卡返回FR_NOT_READY,該如何解決。
    發表于 03-08 07:30

    Linux系統如何擴展文件系統

    當數據盤沒有創建分區,只在設備上創建了文件系統。或者格式化了硬盤,就直接mount上系統使用。
    的頭像 發表于 02-21 09:53 ?834次閱讀

    鴻蒙輕內核源碼分析:虛擬文件系統 VFS

    VFS(Virtual File System)是文件系統的虛擬層,它不是一個實際的文件系統,而是一個異構文件系統之上的軟件粘合層,為用戶提供統一的類 Unix 文件操作接口。由于不同
    的頭像 發表于 02-18 14:50 ?806次閱讀

    全國大學生計算機系統能力大賽操作系統設計賽-LoongArch 賽道廣東龍芯2K1000LA 平臺資料分享

    LoongArch平臺的參考實現。具體的實驗設計參見xv6主頁 的labs標簽頁。 uCore.實驗指導書 rCore. 2022年全國大學生操作系統大賽-功能挑戰賽二等獎。 MaQueOS.
    發表于 02-04 15:37
    主站蜘蛛池模板: 桃花在线视频观看免费| 国产XXXXXX农村野外| 91天仙tv嫩模福利| a级毛片高清免费视频| 不良网站进入窗口软件下载免费 | 久久久久国产精品美女毛片| 久久精品视频91| 人成午夜免费视频| 亚洲国产cao| china18一19 第一次| 国产成人在线免费观看| 男子扒开美女尿口做羞羞的事| 色戒床震视频片段| 99青草青草久热精品视频| 精品人妻伦九区久久AAA片69| 天美麻豆成人AV精品| WWW国产精品人妻一二三区| 兰桂坊人成社区亚洲精品| 亚洲乱码一区二区三区香蕉| 国产白丝JK被疯狂输出视频| 欧美性xxx18一20| 0855福利| 久久精品国产福利电影网| 亚洲电影成人 成人影院| 国产成人无码区免费内射一片色欲| 蜜芽tv在线观看免费网站| 月夜直播免费观看全集| 亚洲乱码中文字幕久久| 国产亚洲精品视频亚洲香蕉视| 亚洲色视在线观看视频| 麻豆精品传媒2021网站入口| 亚洲精品无码久久久久A片空 | 免费高清在线影片一区| 一级毛片西西人体44rt高清| 久久视频在线视频观看精品15| 亚洲色综合中文字幕在线| 国产午夜久久影院| 亚洲国产精品久久无套麻豆| 欧美XXXX69学生HD| 大陆老熟女60岁| 亚洲精品无码AV中文字幕蜜桃|