0 個人信息 張櫻姿 201821121038 計算1812 1 實驗目的 通過編程進一步瞭解文件系統。 2 實驗內容 在伺服器上用Vim編寫一個程式:實現Linux系統命令ls -lai的功能 給出運行結果截圖,對於每一列是如何獲取的,結合源代碼做解釋 3 實驗報告 3.1 ls -lai簡介 l ...
0 個人信息
- 張櫻姿
- 201821121038
- 計算1812
1 實驗目的
- 通過編程進一步瞭解文件系統。
2 實驗內容
- 在伺服器上用Vim編寫一個程式:實現Linux系統命令
ls -lai
的功能 - 給出運行結果截圖,對於每一列是如何獲取的,結合源代碼做解釋
3 實驗報告
3.1 ls -lai簡介
ls -l #以長格式顯示目錄下的內容列表。輸出的信息從左到右依次包括文件名,文件類型、許可權模式、硬連接數、所有者、組、文件大小和文件的最後修改時間等 ls -a #顯示所有檔案及目錄(ls內定將檔案名或目錄名稱為“.”的視為影藏,不會列出) ls -i #顯示文件索引節點號(inode number),一個索引節點代表一個文件
3.2 實現過程
3.2.1 獲取文件信息的函數及文件信息結構體
stat函數:
#include<sys/stat.h> int stat(const char * path,struct stat * buf); /*將path參數(文件或目錄)的文件信息寫到buf中,buf為傳出參數*/
stat結構體:
struct stat{ dev_t st_dev; //設備id號(無需用到) ino_t st_ino; //索引節點號 mode_t st_mode; //許可權與文件類型 nlink_t st_nlink; //硬鏈接數 uid_t st_uid; //用戶id ggid_t st_gid; //所在組id dev_t st_rdev; //設備id,對於特殊文件才有(無需用到) off_t st_size; //大小,較為常用 blksize_t st_blocks; //文件系統I/O的塊大小(無需用到) blkcnt_t st_blksize; //分配的512B(扇區)塊數(無需用到) time_t st_atime; //最後的訪問時間(無需用到) time_t st_mtime; //最後的修改時間,較為常用 time_t st_ctime; //最後的狀態改變時間(無需用到) }
因此,需對上述相應欄位格式化處理。
3.2.2 mode許可權與類型判斷
判斷文件類型的巨集函數:
S_ISREG(m) is it a regular file? //判斷是否是普通文件 S_ISDIR(m) directory? //判斷是否是目錄 S_ISCHR(m) character device? //判斷是否是字元設備 S_ISBLK(m) block device? //判斷是否是塊設備 S_ISFIFO(m) FIFO (named pipe)? //判斷是否是管道文件 S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)//判斷使是否是符號鏈接(軟連接) S_ISSOCK(m) socket? (Not in POSIX.1-1996.) //判斷是否是SOCKET文件
文件許可權巨集變數:
S_IRUSR 00400 //用戶有讀許可權 S_IWUSR 00200 //用戶有寫許可權 S_IXUSR 00100 //用戶有執行許可權 S_IRGRP 00040 //組有讀許可權 S_IWGRP 00020 //組有寫許可權 S_IXGRP 00010 //組有執行許可權 S_IROTH 00004 //其他人有讀許可權 S_IWOTH 00002 //其他人有寫許可權 S_IXOTH 00001 //其他人有可執行許可權
3.2.3 目錄操作函數及目錄信息結構體
opendir函數及readdir函數:
DIR * opendir(const char * name); //打開一個目錄 struct dirent * readdir(DIR *); //讀目錄,依次返回目錄的子項
dirent結構體:
struct dirent{ ino_t d_ino; //子項的i節點 off_t d_off; //節點的偏移量 unsigned short d_reclen;//長度 unsigned char d_type; //子項類型(常用) char d_name[256]; //子文件名(常用) };
3.2.4 表示時間的方式
①秒差形式,1970年1月1日0時0分0秒的秒數差,得到的類型為time_t;
②結構形式,tm結構體:
struct tm{ int tm_sec; //Second [0,60].包含閏秒 int tm_min; //Minutes [0,59]. int tm_hour; //Hour [0,23]. int tm_mday; //Day of month [1,31]. int tm_mon; //Month of year [0,11].(January = 0) int tm_year; //Year Since 1900. int tm_wday; //Day of week [0,6] (Sunday = 0). int tm_yday; //Day of year [0,365].包含閏年 int tm_isdat;//Daylight Savings flag }
電腦大多數情況使用time_t,因為效率高。但是顯示時為tm結構形式。localtime()函數可以實現: time_t 到 tm 的轉換。time_t的指針做參數,返回值tm的指針。
3.3 源代碼
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<time.h> 5 #include<unistd.h> 6 #include<sys/types.h> 7 #include<dirent.h> 8 #include<grp.h> 9 #include<pwd.h> 10 #include<errno.h> 11 #include<sys/stat.h> 12 #include<limits.h> 13 #include<assert.h> 14 15 int flag = 0; 16 //用於分析參數 17 void AnalPara(int argc,char *argv[],char *path) 18 { 19 int i = 0; 20 for(i = 1;i < argc; ++i) 21 { //如果argv[i]中第一個字元是'-',則判斷是l a i中的哪些 22 if(strncmp(argv[i],"-",1)==0) 23 { 24 //參數為a時,把1賦值給flag,flag所在記憶體中第一個位置為1 25 if(strstr(argv[i],"a") != NULL) 26 { 27 flag |= 1 << 0; ////-a參數顯示該隱藏文件 28 } 29 //參數為l時,第二個位置為1 30 if(strstr(argv[i],"l") != NULL) 31 { 32 flag |= 1 << 1; //-l參數顯示該文件的詳細信息 33 } 34 //參數為i時,第三個位置為1 35 if(strstr(argv[i],"i") != NULL) 36 { 37 flag |= 1 << 2; //-i參數顯示該文件的inode number 38 } 39 //位運算可使用一個變數同時標記多個參數是否傳遞 40 } 41 //如果argv[i]中第一個字元不是'-',則判斷所給路徑是直接路徑還是間接路徑 42 else 43 { 44 //直接路徑,copy到path字元數組中 45 if(strncmp(argv[i],"/",1) == 0) 46 { 47 strcpy(path,argv[i]); 48 } 49 //間接路徑,將當前路徑與所給路徑連接 50 else 51 { 52 strcat(path,"/"); 53 strcat(path,argv[i]); 54 } 55 } 56 } 57 } 58 //用於輸出文件名 59 void PrintfFileName(int mode,int uid,char *name) 60 { 61 //是目錄文件 62 if(S_ISDIR(mode)) 63 { 64 //文件名顯示為藍色 65 printf("\33[1;34m%s\033[0m ",name); 66 } 67 //是普通文件 68 else if(S_ISREG(mode)) 69 { 70 if(mode & S_IXUSR||mode & S_IXGRP||mode & S_IXOTH) 71 { 72 if(uid==0) //屬主用戶,文件名顯示為紅色 73 printf("\33[41;37m%s\033[0m ",name); 74 else //其他用戶,文件名顯示為綠色 75 printf("\33[1;32m%s\033[0m ",name); 76 } 77 else 78 { 79 printf("%s ",name); 80 } 81 } 82 else 83 { 84 printf("%s ",name); 85 } 86 } 87 //用於輸出文件詳細信息 88 void PrintMoreInfo(int mode,struct stat st) 89 { //文件許可權判斷 90 char str[10] = {"----------"}; 91 92 if(S_ISDIR(mode)) str[0] = 'd'; 93 if(S_ISCHR(mode)) str[0] = 'c'; 94 if(S_ISBLK(mode)) str[0] = 'b'; 95 96 if(mode & S_IRUSR) str[1] = 'r'; 97 if(mode & S_IWUSR) str[2] = 'w'; 98 if(mode & S_IXUSR) str[3] = 'x'; 99 100 if(mode & S_IRGRP) str[4] = 'r'; 101 if(mode & S_IWGRP) str[5] = 'w'; 102 if(mode & S_IXGRP) str[6] = 'x'; 103 104 if(mode & S_IROTH) str[7] = 'r'; 105 if(mode & S_IWOTH) str[8] = 'w'; 106 if(mode & S_IXOTH) str[9] = 'x'; 107 108 int i = 0; 109 for(; i < 10; i++) 110 { 111 printf("%c",str[i]); 112 } 113 printf(". "); 114 printf("%ld ",st.st_nlink); 115 //輸出屬主 116 struct passwd *pd = getpwuid(st.st_uid); 117 assert(pd != NULL); 118 printf("%4s ",pd->pw_name); 119 //輸出組用戶 120 struct group *gp = getgrgid(st.st_gid); 121 assert(gp != NULL); 122 printf("%4s ",gp->gr_name); 123 //輸出文件大小 124 printf("%4ld ",st.st_size); 125 //輸出最近操作時間 126 struct tm * lchangetime = localtime(&(st.st_mtime)); 127 printf("%d %d %d:%d ",(lchangetime->tm_mon+1),lchangetime->tm_mday,lchangetime->tm_hour,lchangetime->tm_min); 128 } 129 130 int main(int argc,char *argv[]) 131 { 132 char path[128]={0}; 133 //獲取當前路徑 134 getcwd(path,127); 135 //參數分析函數 136 AnalPara(argc,argv,path); 137 //打開該目錄並建立一個目錄流 138 DIR *dir = opendir(path); 139 if(dir == NULL) 140 { 141 char *p = path + strlen(path); 142 while(*p != '/') 143 p--; 144 p++; 145 printf("ls:can not access %s:No such file or directory\n",p); 146 exit(0); 147 } 148 //需要使用dirent結構體中的文件名和文件的inode number 149 struct dirent *dr = NULL; 150 //調用readdir函數獲取該目錄中的目錄項 151 while((dr = readdir(dir)) != NULL) 152 { 153 //當文件名第一個字元是.時,為隱藏文件,不輸出 154 if(((flag&1)==0) && (strncmp(dr->d_name,".",1) == 0)) 155 { 156 continue; 157 } 158 159 struct stat st; 160 char temp[128] = {0}; 161 strcpy(temp,path); 162 strcat(temp,"/"); 163 strcat(temp,dr->d_name); 164 stat(temp,&st); 165 //-li 166 if ((flag&2)==2) 167 { 168 //有參數i 169 if((flag&4)==4) 170 { 171 printf("%ld ",st.st_ino); 172 } 173 //有參數l 174 PrintMoreInfo(st.st_mode,st); 175 PrintfFileName(st.st_mode,st.st_uid,dr->d_name); 176 printf("\n"); 177 continue; 178 } 179 //-ai 180 if((flag&4)==4) 181 { 182 printf("%ld ",dr->d_ino); 183 PrintfFileName(st.st_mode,st.st_uid,dr->d_name); 184 continue; 185 } 186 //-a 187 PrintfFileName(st.st_mode,st.st_uid,dr->d_name); 188 } 189 if(argc == 1||(argc >1&&flag == 0)) 190 printf("\n"); 191 closedir(dir); 192 }
3.4 分析結果
3.4.1 ls -lai運行結果:
3.4.2 ./myls -lai運行結果:
3.4.3 分析輸出格式:
第一列為文件/目錄的索引編號(inode number),如果是目錄,則使用dirent結構體中的d_ino獲取;如果是文件,則使用stat結構體中的st_ino獲取。
第二列為文件的許可權,第一位的-表示不同的文件類型(普通文件,管道文件)。後面九位分別表示,該文件的屬主,組用戶和其他用戶的讀、寫、執行三種不同的許可權。
第三列為文件的硬鏈接數,如果是一個目錄,則第2欄位表示該目錄所含子目錄的個數。使用stat結構體中的st_nlink獲取。
第四列為屬主用戶,使用stat結構體中的st_uid獲取。
第五列為組用戶,使用stat結構體中的st_gid獲取。
第六列為文件所占用的大小,以位元組為單位,如果是目錄文件,則表示該目錄的大小,而不是該目錄下所有文件的大小。使用stat結構體中的st_size獲取。
第七列為最後修改時間,使用stat結構體中的st_mtime獲取。
第八列為文件名,使用dirent結構體中的d_name獲取。
4 References
- https://blog.csdn.net/apollon_krj/article/details/54710135
- https://www.cnblogs.com/cherishry/p/5885107.html
- https://blog.csdn.net/jialexiao/article/details/71124930
- https://blog.csdn.net/longerzone/article/details/23870297
- https://blog.csdn.net/dream_allday/article/details/75243818
- https://blog.csdn.net/daoer_sofu/article/details/102456935