FILE*fopen(constchar*restrictfilename,constchar*restrictmode);2>size_tfwrite(constvoid*restrictbu" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

轉:linux文件讀寫

系統 1976 0

讀寫文件,是作為一個操作系統所提供的最基本接口之一。

我們就從寫文件過程:open,write,close這幾個接口來說起,描述寫文件的那些事兒。

平時,我們做應用程序的時候,常常用到讀寫文件的函數接口,就拿寫文件來說,我們用C/C++編寫時,用到了以下的函數接口:
1>? ?FILE* fopen(const char* restrict filename,const char* restrict mode);
2>? ?size_t fwrite(const void* restrict buffer,size_t size,size_t n,FILE * restrict fp);
3>? ?int fclose(FILE * fp) ;

以上這幾個函數接口大家都比較熟悉,如果按照這個來分析似乎更加明了。然而,上面的這些接口已經是現代版本的接口,其實現依賴于現在的成熟系統,分析現行系統的龐大代碼我還嫩了點,所以就拿過去版本的linux系統和一些原始接口進行分析吧。(其實大家都知道,現行操作系統內核的代碼量已經不是一個人一輩子能看完的了,我們主要是借鑒linux的系統思想,去作我們自己的嵌入式操作系統)

老版本的接口是這個樣子的:
1>? ?int open(const char* filename,int flag,...) ;
2>? ?int write(int fildes,const char* buf,off_t count) ;
3>? ?int close(int fildes) ;

這幾個接口的聲明在頭文件中,實現在系統的LIB庫文件中,所以使用的時候,我們只需要包含幾個相應的頭文件,然后使用接口,在編譯的時候,編譯器把LIB庫文件中的二進制實現鏈接進去,這樣就行了。

當然,僅僅是使用不是本文的目的,我們是要探究的是這個使用的背后是什么,操作系統為我們做了什么。

首先,庫文件中的open是怎么實現的呢?
int open(const char * filename,int flag,...){
? ?register int res ;
? ?va_list arg ;
? ?va_start(arg,flag) ;
? ? __asm__("int $0x80"
??????????????????: "=a"(res)?????
??????????????????:""(__NR_open),"b"(filename),"c"(flag),"d"(va_arg(arg,int))

?????????????????

?????????????????
?????????????????);
? ?if(res>=0)
? ? ? ? ? ? ? ?return res ;
? ?errno = -res ;
? ?return -1 ;
}

庫文件中的open函數封裝了匯編代碼“ 調用系統 ”,這個系統調用的 返回值 通過 eax寄存器 傳遞給了 res ,系統調用的 輸入參數 分別存放在 ebx,ecx,edx寄存器 中。

系統調用是一個中斷,是由匯編語言 int ? 中斷號 促發,所以好多教材上稱其為軟中斷或軟件中斷。

系統中斷中斷發生,cpu停止當前任務的處理,把用戶態的五個關鍵信息保存在內核態棧中,分別是:eflag,ss,esp,eip和cs寄存器,他們記錄著進程用戶態的關鍵信息(恢復用戶態運行時用到),把他們壓棧到內核棧中。當然,內核棧地址在進程結構信息中早有記錄,上邊的五個寄存器的 用戶態信息保存與賦予內核態信息 這個過程是由CPU自動完成的,只要我們在前邊的任務數據結構中設置好了就行。

任務運行在內核態中,這里有一切系統的代碼(包括各種中斷處理程序和文件系統以及各種設備的驅動程序)。

呃。。。寫博客好費時間啊,不過也是個再次詳細學習的過程,值了,畢竟能說出來才說明掌握的透徹,不像現在,邊寫邊翻資料。。。吃飯去了,回來再寫。。。

呵呵,再次拿起來這個帖子,都過去一周了。接著寫,總比玩游戲強。

依據中斷向量表的設置,程序運行到軟中斷處理程序的入口處(此時,用戶態的關鍵信息eflag,ss,esp,eip和cs都已經保存到內核棧中了),在這里(是用匯編寫的)手工壓棧保存用戶態的其他信息,注意,這里的保存,在中斷退出時,還要手工退棧恢復原:
push %ds
push %es
push %fs
pushl? %eax
pushl %edx
pushl %ecx
pushl %ebx
???

movl? $0x10 ,%edx? ? ? ? ? ? ? ? ? ? ? ?#0x10即 0001,0 0 00? ( 綠色 兩位是請求特權級, 紅色 一位是GDT(0)/LDT(1), 藍色 四位是第幾項),這么說,edx寄存器中放的是GDT表的第 0x001,0 +1項(即第3項,0x0000是第一項),是 系統數據段的選擇符

#把
系統數據段的選擇符 放入ds和es寄存器中,則用到的數據都將是系統數據段(ds指示)中的數據。
mov %dx,%ds
mov %dx,%es

movl? $0x17, %edx? ? ? ? ? ? ? ? ? ? ?#0x17即 0001,0 1 11? ( 綠色 兩位是請求特權級, 紅色 一位是GDT(0)/LDT(1), 藍色 四位是第幾項),這么說,edx寄存器中存放的是LDT表的第 0x001,0 +1項(即第3項,0x0000是第一項),是 用戶態數據段的選擇符

#把
用戶態數據段的選擇符 放入 fs 寄存器中,則可以通過fs寄存器來實現從 內核態 讀/寫 用戶態 的數據(在內核中,有好多這樣的操作,諸如:get_fs_long(),set_fs_long(),get_fs_word(),set_fs_word()等等)。
mov %dx, %fs

......
call _sys_call_table(,%eax,4)
pushl? %eax??????? #把eax中的返回值壓入棧
......

#中斷返回時候,手工恢復各寄存器成用戶態時的內容

popl? %eax ? ? ? ? ? ? ? ?#保存著系統調用的返回值,放入eax,在用戶態的庫函數open中的返回值就是通過這里的eax傳遞的。

popl %ebx
popl %ecx
popl %edx

#此時,理論上應該 popl %eax 了,但是。。。
addl $4,%esp ? ? ? ? ?#放棄 系統中斷調用時的 壓棧保存的eax(上邊 紅色eax 保存著 中斷的向量號碼)

pop %fs
pop %es
pop %ds
iret? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#中斷返回

上邊的 call _sys_call_table(,%eax,4) 就是調用具體的系統調用 中斷處理函數,_sys_call_table是定義在其他文件中定義的 函數指針 數組
fn_ptr sys_call_table[sys_setup,sys_exit,sys_fork,sys_read,sys_write, sys_open ,......];

fn_ptr :typedef int (*fn_ptr)() ;

sys_open:extern int sys_open() ;

可以看到,sys_open在數組的第六項,這就對應了上邊在用戶態定義的
#define __NR_open??5
? extern int sys_open 對應的 實現函數在另外的文件 fs/open.c 所實現:
int sys_open(const char* filename,int flag,int mode){

?????struct m_inode *? inode ?;
?????struct file * f ;
?????int i,fd ;

?????for(fd=0;fd<NR_OPEN;fd++){

?????

??????????if( !current->filp[fd] ) break ;?
?????}

????
?????f = 0 + file_table ;

????
?????for(i=0;i<NR_FILE;i++,f++){

??????????if(!f->f_count) break ;
?????}

????
?????current->filp[fd] = f ;

????? open_namei( filename,flag,mode, &inode ) ;
????
?????f->f_mode = inode->i_mode ;
?????f->f_flags = flag ;
?????f->f_count = 1 ;

????
????? f->f_inode = inode ;
?????f->f_pos = 0 ;
?
????
? ?
?????return (fd) ;?

??????
}

int open_namei(const char* pathname,int flag,int mod,struct m_inode ** res_inode){

?????struct m_inode * dir,* inode ;

?????struct buffer_head * bh ;

?????struct dir_entry * de ;

?????dir =? dir_namei( pathname,&namelen,&basename,NULL ) ;

?????bh =? find_empty( &dir,basename,namelen,&de ) ;

?????if(!bh){

???????????inode = new_inode(dir->i_dev) ;

???????????inode->i_uid = current->euid ;
???????????inode->i_mode = mode ;
???????????inode->i_dirt = 1 ;

???????????bh = add_entry(dir,basename,namelen,&de) ;

???????????de->inode = inode->i_num ;
???????????de->b_dirt = 1 ;
?????????
???????????brelse(bh) ;
???????????iput(dir) ;
???????????* res_inode = inode ;

???????????return 0 ;
?????}

?????inr = de->inode ;
?????dev = dir->i_dev ;

?????brelse(bh) ; ?

?????inode = follow_link(dir,iget(dev,inr)) ;

?????*res_inode = inode ;

?????return 0 ;
}

呵呵,文件系統是操作系統最復雜的部分,所以代碼量也最大,先寫到這里,再有空了接著寫,總不能不工作,天天寫這個東西呀。這是學習,學習就是為了更好的工作,不工作了哪行。下次接著寫,呵呵

轉自: http://blog.sina.com.cn/s/blog_61869e800100ek8w.html

轉:linux文件讀寫


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产亚洲精 | 国产亚洲一区二区三区在线 | 国产福利影院在线观看 | 欧美一区二区三区黄色 | 欧美a在线观看 | 狠狠综合久久综合网站 | 免费黄色的视频 | 久99久爱精品免费观看视频 | 日批日韩在线观看 | 国产午夜亚洲精品第一区 | 26uuu欧美日韩国产 | 骚黄视频| 成人深夜视频在线观看 | 中国欧美一级毛片免费 | 波多野结衣视频一区 | 天堂一区二区三区在线观看 | 99免费在线播放99久久免费 | 久久精品亚洲一区二区 | 成人久久18网站 | 国精品在亚洲_欧美 | 青娱乐91视频 | 亚洲黄色a | 亚洲精品久久久久久久网站 | 欧美在线观看一区二区 | 国产在线精品香蕉综合网一区 | 日韩免费高清 | 国产小视频免费在线观看 | 四虎精品福利视频精品 | 操美女免费看 | 情趣色视频网站 | 成 人 免 费 黄 色 | 午夜性色福利视频在线视频 | 99视频网址| 久久久久国产精品美女毛片 | 性大特级毛片视频 | 五月婷婷在线免费观看 | 国产欧美精品一区二区三区–老狼 | 亚洲激情网站 | 九色官网| 色吧五月婷婷 | 中文字幕日本一区波多野不卡 |