jasmine214--love

          只有當你的內心總是充滿快樂、美好的愿望和寧靜時,你才能擁有強壯的體魄和明朗、快樂或者寧靜的面容。
          posts - 731, comments - 60, trackbacks - 0, articles - 0
          最近在學習Unix下系統編程,書看的還比較仔細,但是合上書后總是有種霧里看花朦朦朧朧的感覺。俗話說實踐出真知,學習編程怎么能不動手呢。既然是學習系統編程那就寫一些系統命令來鞏固知識,消除朦朧的感覺吧!選中PWD命令,有如下幾個原因:
                    1、 可以加深對Linux文件系統組織結構的理解
                    2、 可以加深對目錄結構的理解
                    3、 可以加深對掛載點和鏈接的理解


          注:關于LINUX文件系統的相關基礎知識,大家可以先看看《Linux文件系統詳解》:http://www.armjishu.com/bbs/viewtopic.php?id=1754 &flag=1578

                   Unix下一切皆文件,也就是說掌握好了文件也就掌握了Unix的一切(菜鳥說法不必當真)。掌握了上述三個知識點也就算基本掌握了Unix文件系統的相關知識。有點遺憾的是文件狀態和權限相關知識在這個例子中沒有涉及。選好了命令下一步就是寫了,下面是我的寫作計劃:
          1、 Unix的文件系統的內部結構,主要是超級塊、inode相關知識
          2、 目錄結構,當然是目錄相關知識了
          3、 編寫PWD命令
                   PWD命令的作用就是顯示當前工作目錄的絕對路徑,就是從/開始到當前目錄。用法很簡單,沒有其他參數。在命令行敲入pwd:

          點擊看大圖


          pwd命令.jpg



          1、Unix文件系統的內部結構
              文件系統可以用來存儲文件內容、文件屬性(所有者、日期等)和目錄,這些不同類型的數據是如何存儲在磁盤上的呢?Linux使用了一個簡單的辦法。如下圖所示它將磁盤分成了3部分:超級塊、inode表和數據區。

          點擊看大圖


          文件的內部結構



                超級塊,通常是文件系統的第一個塊,用來存放文件系統本身的信息。例如每個區域的大小、未被使用的磁盤塊的信息等;不同版本的Unix的超級塊的內容和結構稍有不同。
                inode表,每個文件都有一些屬性,如大小、文件所有者和最近修改時間等。這些屬性被記錄在inode表中,所有的inode都有相同的大小。文件系統中的每個文件都對應一個inode;
                數據區,文件內容的內容保存在這個區域。磁盤上所有塊的大小都是一樣的,如果文件包含了超過一個塊的內容,則文件內容會存放在多個磁盤塊中。
                當創建一個新文件時,內核將文件內容存放在數據區,文件屬性存放在inode中,文件名存放在目錄中。當對一個文件進行相關操作時,內核先在目錄中找到 文件名,然后根據目錄中inode獲得文件的屬性,最終找到文件的內容。從上述過程可以看出,目錄至少需要包含inode和文件名。

          2、目錄結構
             用戶看到的文件系統是目錄和子目錄的集合,也就是目錄樹。每個目錄能夠包含文件和子目錄,每個子目錄有一個父目錄,這棵樹的結構常用線條連接的方框圖來 表示。在文件系統內部,目錄是一個包含文件名與inode節點對的列表的文件。從用戶角度看到的是一個文件名的列表,而從系統的角度看到的是一個被命名的 指針的列表。如下圖所示:

          點擊看大圖


          目錄樹的兩種不同視圖



                一般我們都說文件存放在某個目錄中,但是由上面的分析可知目錄中存放的只是文件在inode表的入口,而文件內容則存儲在數據區。'文件x在目錄a中 ',意味著在目錄a中有一個指向inode402的鏈接,這個鏈接所附加的文件名為x。簡短的說,目錄包含的是文件的引用,每個引用被稱為鏈接。
                鏈接有兩種,一種是硬鏈接,另一種是符號鏈接。這里需要注意的一點是Unix下文件沒有文件名,但是鏈接有名字,通常所說的文件名其實就是鏈接名。硬鏈 接就是把鏈接名和inode鏈接起來,也就是將文件名和文件本身鏈接起來。符號鏈接就是通過名字引用文件,而不是inode,也就是將名字和名字鏈接起 來。
                從圖1我們可以看到,在系統角度,每個目錄都有兩個鏈接:'.'和'..'。這兩個鏈接是干什么用的呢?內核在每個目錄都設置了一個指向目錄本身的inode,這個入口被稱為'.'。'..',是指向父目錄inode的入口。

          3、編寫PWD命令
          3.1、PWD分析
                通過前面基礎知識的學習,我們知道了Unix文件系統是樹形結構,節點被稱為inode,指針的集合被稱為目錄,葉子節點被稱為鏈接。那么要想取得當前 工作目錄的絕對路徑只需追蹤鏈接,讀取目錄,一個目錄接著一個目錄沿著樹向上追蹤,每步查看'.'的inode,然后在父目錄中查找該inode的名字, 直到到達樹的根部。這就是PWD命令的工作原理,知道了原理那么就可以得出PWD的實現算法了:
                     1、得到'.'的inode,稱其為n(使用stat)
                     2、進入'..'(使用chdir)
                     3、找到節點號為n的inode鏈接的名字(使用opendir、readdir、closedir)
                     4、重復上述三個步驟,直到到達書的根部
                  這里需要注意兩個問題,第一個問題就是如何知道已經到達樹的頂端。在Unix 文件系統的根目錄中,'.' 和 '..'指向同一個inode。因此當PWD命令重復循環直到一個目錄的'.' 和 '..'的inode相同時,就可以認為已經到達文件樹的根部了。第二個問題就是如何以正確的順序顯示目錄名字。學過算法的同學都知道,處理這種問題用遞歸再合適不過了。通過一個遞歸的程序逐步到達樹的頂端來一個接一個地顯示目錄名,從而避免了字符串的管理。

          3.2、相關數據結構和系統調用
              在動手寫代碼之前需要了解一下兩個數據結構:DIR和struct dirent。DIR是一個不透明的結構,每個平臺都有自己的DIR實現,用戶不需要明白DIR的具體結構。也就是說,看到源碼中的DIR就只需要明白這是個目錄指針就可以了。struct dirent是一個目錄入口的結構,在Linux下定義如下:

          1. struct dirent{  
          2.     long d_ino;   /* inode number 索引節點號 */  
          3.     off_t d_off;  /* offset to this dirent 在目錄文件中的偏移 */  
          4.     unsigned short d_reclen;    /* length of this d_name 文件名長 */  
          5.     unsigned char d_type;        /* the type of d_name 文件類型 */  
          6.     char d_name [NAME_MAX+1];   /* file name文件名,最長255字符 */  
          7. }  

          與目錄操作有關的函數在dirent.h頭文件中聲明。它們以DIR結構為目錄操作的基礎,其使用方法與文件流(FILE *)類似。目錄數據項本身在struct dirent結構中返回。我們實現PWD命令需要用到的目錄操作有opendir、readdir和closedir,下面就介紹下這三個函數:

          DIR *opendir(const char *name)
          opendir函數用來打開一個目錄并創建一個目錄流,如果成功則返回一個指向DIR結構的指針,該指針用于讀取目錄數據項。

          struct dirent *readdir(DIR *dirp)
          readdir函數返回一個指針,指針指向的結構保存著目錄流dirp中下一個目錄項的相關資料。后續的readdir調用將返回后續的目錄項。

          int closedir(DIR *dirp)
          closedir函數用來關閉一個目錄流并釋放與之相關的資源,成功返回0,失敗返回-1。

          3.3、編譯運行
               進入到存放spwd.c文件的目錄下,使用gcc編譯源文件,生成可執行文件(我這里命名為spwd),然后把可執行文件拷貝到/bin/下就可以像使用pwd命令一樣使用自己寫的pwd命令了。

          點擊看大圖


          112.JPG


          原文: http://blog.csdn.net/humchx/archive/2009/09/04/4517828.aspx


          主站蜘蛛池模板: 固原市| 龙陵县| 山西省| 万安县| 随州市| 新疆| 无极县| 大竹县| 五河县| 株洲市| 六盘水市| 鹿泉市| 高邮市| 原平市| 交城县| 集贤县| 新巴尔虎右旗| 平江县| 怀化市| 泗水县| 建阳市| 阿拉善盟| 明星| 唐山市| 苍溪县| 龙游县| 积石山| 贺州市| 肇州县| 屯昌县| 北安市| 汨罗市| 札达县| 阜宁县| 新宁县| 攀枝花市| 准格尔旗| 于都县| 招远市| 丰城市| 镇平县|