++++++++++++++++++++++++++++++++++++++++++
本文系本站原創,歡迎轉載! 轉載請註明出處:
http://blog.csdn.net/mr_raptor/article/details/6844692
++++++++++++++++++++++++++++++++++++++++++
當我們用ls –l filename,這個shell命令時,會列印出,檔案的詳細資料,如:
這些檔案的詳細資料是存放在一個結構體stat裡面的,當檔案系統運行起來後,它從磁碟裡面將檔案詳細資料載入到核心空間記憶體裡,使用者空間可以通過系統調用函數stat(),fstat()來取得這個結構體的資訊。
Stat結構體:
struct stat {
dev_t st_dev; /* 檔案系統裝置號 */
ino_t st_ino; /* i結點號 */
mode_t st_mode; /* 檔案類型,許可權位 */
nlink_t st_nlink; /* 永久連結數 */
uid_t st_uid; /* 主人使用者ID */
gid_t st_gid; /* 主人組ID */
dev_t st_rdev; /* 特殊檔案裝置號 */
off_t st_size; /* 檔案位元組大小 */
blksize_t st_blksize; /* 塊大小 */
blkcnt_t st_blocks; /* 檔案所佔塊個數 */
time_t st_atime; /* 上次訪問時間 */
time_t st_mtime; /* 上次修改時間 */
time_t st_ctime; /* 上次檔案狀態修改時間 */
};
首先,其類型被typedef過了,因此看不出其類型來,可以通過grep命令來查看(具體操作看第一節),我們對比著檔案資訊來看,基本上這一個結構體,將整個的檔案的基本資料都包含了,通過讀取這個結構體,就能實現一個簡單的ls –l的shell命令了。
Stat函數
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
功能:查看檔案或目錄屬性
參數:path是檔案的路徑, buf就是stat結構體的指標。
傳回值:成功返回0,錯誤返回-1
現在通過這個函數我們可以取得stat結構體了,那麼通過讀結構體就能得到ls –l 一樣的效果了。
我們來看一個例子:
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char * argv[])
{
if(argc != 2) {
printf("Usage: <pathname>\n");
}
int i = 0;
struct stat buf;
if(stat(argv[1], &buf) < 0) {
perror("stat");
}
printf("%d %d %d %d %d %d %s\n", buf.st_mode,
buf.st_nlink, buf.st_uid, buf.st_gid,
buf.st_size, buf.st_atime, argv[1]);
return 0;
}
運行結果:
我們發現,除了永久連結數,檔案大小,檔案名稱一樣,其它全部都不一樣。
看來還有很多東西要處理下,我們來分析下。
首先是st_mode,它是一個int型的成員,而ls –l顯示出來是字串
st_uid, st_gid這兩個也是int型成員,而ls是使用者名稱
日期就更沒有譜了,完全不一樣。這些問題我們一一解決。
先來看st_mode。
S_ISUID 執行時設定-使用者- I D
S_ISGID 執行時設定-組- I D
S_ISVTX 儲存本文
S_IRWXU 使用者(所有者)讀、寫和執行
S_IRUSR 使用者(所有者)讀
S_IWUSR 使用者(所有者)寫
S_IXUSR 使用者(所有者)執行
S_IRWXG 組讀、寫和執行
S_IRGRP 組讀
S_IWGRP 組寫
S_IXGRP 組執行
S_IRWXO 其他讀、寫和執行
S_IROTH 其他讀
S_IWOTH 其他寫
S_IXOTH 其他執行
這些許可權在前面的open時,就有學過,它們都是用的一套宏定義。
我們用grep得到其值,再轉化成二進位分別為:
由此圖我們可以輕易的看出,其實每一個許可權位對應一個bit,當該位元為1證明擁有此許可權,為0,沒有許可權,這也能說明,當時為什麼我們用chomod 修改使用者權限時,加上777表示擁有全部許可權。
因此我們要想實現ls –l顯示檔案許可權功能,只要將其mode值和對應標誌相與即可判斷出是否具有許可權。
if( buf.st_mode & S_IRUSR )
putchar(‘r’);
else
putchar(‘-‘);
我們要注意下,如果用ls –l 目錄名,那麼許可權位第一位上顯示是d,如果是檔案其顯示的是-,這也說明,我們還要去判斷一個檔案的類型。其原理和上面檔案許可權非常相似。
因此我們也可以用類似的方法得到其類型:
if( buf.st_mode & S_IFREG )
putchar(‘-’);
if( buf.st_mode & S_IFDIR )
putchar(‘d‘);
但是系統給我們已經提供了幾個宏,如下:
因此可以通過這幾個宏來代替我們的與運算:
if(S_ISREG(buf.st_mode)
putchar(‘-‘);
if(S_ISDIR(buf.st_mode)
putchar(‘d‘);
通過上面對st_mode成員的分析我們可以得出這樣的結論,st_mode用了16個bit來表示一個檔案的類型和許可權,這樣又節省了記憶體資源,運用位元運算還能加快其運算速度。總結一下如:
現在我們來看怎樣取得使用者名稱。
我們通過st_uid和st_gid可以取得主人使用者ID和組ID,我們應該還記得在剛開始學習linux基本操作和shell編程的時候,有說到,/etc/passwd裡面存放的是使用者的帳號資訊,其內容如下所示:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
它們都用 : 分開來的,其中,第一個是使用者名稱,第三個是其對應的使用者ID,我們可以通過讀取passwd檔案內容來取出對應的使用者名稱。通過讀取/etc/group檔案來取得組名。
如果你不想去這樣寫這個函數,我們的系統調用介面也提供了這樣一個通過ID取其使用者名稱和組名的函數:
getpwuid();
getgrgid();
這兩個函數的具體的用法自己去man 吧,要不就自己通過讀passwd的方法來取。嘿嘿!
最後一個,顯示時間。
這個要瞭解一個Linux裡面的時間機制,系統裡面的時間是用一個很大的數來表示的,它是指的從1970年1月1日(UTC)開始到目前時間所經過的秒數,因此它是個很大的數,既然它是個秒數,那我們就能把它轉化成當前的時間,這個我們直接使用庫函數就行了。因為時間的顯示格式有很多種,因此要對轉化後的日期時間也要轉化下。
localtime()將秒數時間轉化成一個本地時區的時間結構體,再通過strftime()將時間以格式列印出日期來。這兒也自己去man 一下。
進階篇
我們通過上面所講的可以寫出一個最簡單的ls –l 的命令了,但是還有很多細節沒有考慮到,看下面:
上面的test.txt檔案,當它的使用者權限擁有執行許可權時,設定它的s位,那麼顯示的是小寫s,當使用者權限沒有執行許可權時,它的s位是大寫的S,因此這兒也要將我們的ls –l再進一步的修改。同樣t位也用同樣的方式顯示。
當我們將修改使用者主人時,可以指定一個uid,比如下面,設定檔案的主人是uid為9999的主人,但是以9999為使用者id的使用者並不存在,系統ls 會像下面這樣顯示,直接顯示出它的uid並不會顯示其使用者名稱。
當顯示一個檔案的詳細資料時,如果這是一個普通檔案,沒有什麼問題,但是如果當前檔案是一個連結檔案的話,系統的ls會像下面那樣顯示:
它列印的是(連結檔案)的詳細資料,後面跟出了連結檔案指向的檔案(Linux裡面的連結檔案和我們windows裡的捷徑很相似)這兒就要多考慮一點了,如果當前檔案是一個連結檔案,還要列印出,這個連結檔案所指向的檔案。這兒用到readlink系統調用,這個自己去man 一下,very easy。
當顯示多個檔案的時候,我們注意一下系統ls –l 它總是排列的很整齊,可見,它在列印資訊的時候,取的當前列裡最長的字元的長度列印的,同時還有它的檔案名稱是按照降序排列的。
++++++++++++++++++++++++++++++++++++++++++
本文系本站原創,歡迎轉載! 轉載請註明出處:
http://blog.csdn.net/mr_raptor/article/details/6844692
++++++++++++++++++++++++++++++++++++++++++