??在上篇文章中我們跟蹤ls命令看到了其所使用的這么幾個系統呼叫:stat、openat、fstat、getdents、close、write等,這里再簡單介紹下這幾個系統呼叫的功能:
??stat:為獲取檔案狀態系統呼叫
??openat:將打開目錄/data獲取它的檔案描述符,回傳值3即為檔案描述符;
??fstat:獲取檔案描述符為3的檔案狀態
??getdents64:獲取檔案描述符為3的目錄項
??close:關閉檔案描述符3
??write:在獲取到檔案目錄資訊后將引數2中的資訊標準輸出到控制臺
系統呼叫
??在golang中已經給我們封裝好了系統呼叫的相關函式,只要呼叫相關函式傳入所對應的引數即可,go中的系統呼叫相關函式都放在syscall包下,如在呼叫sys_getcwd,獲取當前作業目錄的絕對路徑:
//接收目錄位元組陣列
dir:=make([]byte,100)
//呼叫sys_getcwd系統呼叫
n,e:= syscall.Getcwd(dir)
fmt.Println(string(dir))
實作ls
??在Linux中將所有的設備都當做檔案來處理,用檔案描述符來標識每個檔案物件;標準輸入、標準輸出、標準錯誤的檔案描述符分別為:0、1、2;
ls指令的具體實作流程為:獲取目錄狀態、獲取目錄項、獲取檔案狀態、獲取用戶資訊;
??在呼叫getdents64系統呼叫獲取目錄項時需要傳入該目錄的檔案描述符,所以需提前獲取該目錄的檔案描述符;
具體的實作流程為:

狀態物件stat
st_ino 與該檔案關聯的inode
st_dev 保存檔案的設備
st_uid 檔案屬主的UID號
st_gid 檔案屬主的GID號
st_atime 檔案上一次被訪問的時間
st_ctime 檔案的權限、屬主、組或內容上一次被修改的時間
st_mtime 檔案的內容上一次被修改的時間,(和st_ctime的不同之處顯而易見)
st_nlink 該檔案上硬連接的個數
dir目錄物件
d_ino int64 //索引節點
off_t int64 //目錄中檔案偏移
reclen int16 //長度
d_type int8 //檔案型別
d_name []byte //檔案名
用戶資訊: 所屬用戶、所屬組、
權限資訊: 目錄、檔案、符號鏈接、讀寫執行
實作偽代碼:
//獲取目錄檔案描述符 只讀|非阻塞|打開目錄|執行系統呼叫時關閉檔案描述符(自動關閉)
fd,e := syscall.Openat(-0x64,path,syscall.O_RDONLY|syscall.O_NONBLOCK|sysc all.O_DIRECTORY|syscall.O_CLOEXEC, 0666)
//獲取目錄狀態
e := syscall.Lstat(path, dirStat)
var b = make([]byte, dirStat.Size)
//獲得目錄項
n, e := syscall.Getdents(fd, b)
buf := bytes.NewBuffer(b)
//目錄資訊
dir := &dirent{}
var c = 0
//遍歷獲取目錄資訊
for ; c < n; {
_ = binary.Read(buf, binary.LittleEndian, &dir.d_ino)
binary.Read(buf, binary.LittleEndian, &dir.off_t)
binary.Read(buf, binary.LittleEndian, &dir.reclen)
binary.Read(buf, binary.LittleEndian, &dir.d_type)
//名稱長度
nLen := dir.reclen - 19
name := buf.Next(int(nLen))
dir.d_name = name[:len(name)-1]
//獲取目錄中檔案狀態資訊
e := syscall.Stat(filePath, stat)
if e != nil {
fmt.Println(e.Error())
}else {
mode := stat.Mode
m := parserAuth(mode)
//使用uid獲取用戶名
u, e := user.LookupId(strconv.Itoa(int(stat.Uid)))
if e == nil {
//使用gid獲取組名
g, _ := user.LookupGroupId(u.Gid) //mtim 最后一次修改檔案時間,atim 最 后一次訪問檔案時間 ctim最后一次改變檔案狀態時間
opt:=&option{m,u.Username,g.Name,int(stat.Size),time.Unix(stat.Mtim.Unix()).Format(TIME_LAYOUT), string(dir.d_name)}
list = append(list, opt)
}
}
c = c + int(dir.reclen)
}
程式執行:

文章首發地址:https://mp.weixin.qq.com/s/Xn_xUHei10sgWkqEhMZo5g
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/301869.html
標籤:其他
