- 姓名:吕煜华
- 学号:201821121046
- 班级:计算1812
1. 编写程序
在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai
的功能,给出源代码。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<dirent.h> 6 #include<sys/stat.h> 7 #include<sys/types.h> 8 #include<time.h> 9 #include<fcntl.h> 10 #include<pwd.h> 11 #include<grp.h> 12 13 void error_printf(const char*); 14 void list_dir(const char*); 15 void list_message(const char*, const struct stat*); 16 void file_type(const struct stat*); 17 void file_power(const struct stat*); 18 void file_id(const struct stat*); 19 void file_mtime(const struct stat*); 20 void link_printf(const char*); 21 22 void error_printf(const char* funname){ 23 perror(funname); 24 exit(1); 25 } 26 27 void list_dir(const char* pathname){ 28 DIR* ret_opendir = opendir(pathname); //打开目录 29 if(ret_opendir == NULL) 30 error_printf("opendir"); 31 32 int ret_chdir = chdir(pathname); //转到”pathname“,便于stat函数的使用 33 if(ret_chdir == -1) 34 error_printf("chdir"); 35 36 struct dirent* ret_readdir =NULL; 37 while(ret_readdir = readdir(ret_opendir)) 38 { 39 char* filename = ret_readdir->d_name; //获取文件名 40 struct stat file_message ={}; 41 int ret_stat = lstat(filename, &file_message); //获取文件信息 42 if(ret_stat == -1) 43 printf("%s error!", filename); 44 else if(strcmp(filename,".") && strcmp(filename, "..")) 45 list_message(filename, &file_message); 46 } 47 } 48 49 void list_message(const char* filename, const struct stat* file_message){ 50 file_type(file_message); // 判断打印类型 51 52 printf("%d ",(int)file_message->st_ino); //添加索引号 53 file_power(file_message); //判断并打印文件权限 54 printf("%3ld ",file_message->st_nlink); //打印硬链接数 55 file_id(file_message); //转换并打印用户id与组id 56 printf("%5ld ", file_message->st_size); //打印文件大小 57 file_mtime(file_message); //打印文件最后修改时间 58 printf("%s ", filename); //打印文件名 59 if(S_ISLNK(file_message->st_mode)) //如果是软链接文件打印其指向的位置 60 link_printf(filename); 61 puts(""); 62 } 63 64 void file_type(const struct stat* file_message){ 65 mode_t mode = file_message->st_mode; 66 67 if(S_ISREG(mode)) printf("-"); //普通文件 68 else if(S_ISDIR(mode)) printf("d"); //目录文件 69 else if(S_ISCHR(mode)) printf("c"); //字符设备文件 70 else if(S_ISBLK(mode)) printf("b"); //块设备文件 71 else if(S_ISFIFO(mode)) printf("p"); //管道文件 72 else if(S_ISLNK(mode)) printf("l"); //链接文件 73 else printf("s"); //socket文件 74 } 75 76 void file_power(const struct stat* file_message){ 77 mode_t mode = file_message->st_mode; 78 79 printf("%c", mode&S_IRUSR?'r':'-'); 80 printf("%c", mode&S_IWUSR?'w':'-'); 81 printf("%c", mode&S_IXUSR?'x':'-'); 82 83 printf("%c", mode&S_IRGRP?'r':'-'); 84 printf("%c", mode&S_IWGRP?'w':'-'); 85 printf("%c", mode&S_IXGRP?'x':'-'); 86 87 printf("%c", mode&S_IROTH?'r':'-'); 88 printf("%C", mode&S_IWOTH?'w':'-'); 89 printf("%c ", mode&S_IXOTH?'x':'-'); 90 } 91 92 void file_id(const struct stat* file_message){ 93 struct passwd* pwd; 94 pwd = getpwuid(file_message->st_uid); 95 printf("%s ", pwd->pw_name); 96 97 struct group* grp; 98 grp = getgrgid(file_message->st_gid); 99 printf("%s ", grp->gr_name); 100 } 101 102 void file_mtime(const struct stat* file_message){ 103 struct tm* t = localtime(&file_message->st_mtime); 104 printf("%2d月%2d日 %2d:%2d ", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm _min); 105 } 106 107 void link_printf(const char* filename){ 108 char buf[1024] = "123"; 109 if(0 == readlink(filename, buf, sizeof(buf))) 110 error_printf("readlink"); 111 printf("-> %s ", buf); 112 } 113 114 int main() 115 { 116 char path[1024] = {}; 117 strcpy(path, "./"); 118 struct stat file_message={}; 119 120 int ret_stat = lstat(path, &file_message); 121 if(ret_stat == -1) 122 error_printf("stat"); 123 124 if(S_ISDIR(file_message.st_mode)) //判断是否为目录 125 list_dir(path); 126 else 127 list_message(path, &file_message); 128 return 0; 129 } 130
2. 分析运行结果
给出运行结果截图,对于每一列是如何获取的,结合源代码做解释
分析结果如下:
(1)第一列为文件索引号
printf("%d ",(int)file_message->st_ino);//添加索引号
(2)第二列首字母为文件类型,后面的 “r” 、“w”、“x”为读、写、执行的权限。
void file_type(const struct stat* file_message) { mode_t mode = file_message->st_mode; if (S_ISREG(mode)) printf("-"); // 普通文件 else if(S_ISDIR(mode)) printf("d"); // 目录文件 else if(S_ISCHR(mode)) printf("c"); // 字符设备文件 else if(S_ISBLK(mode)) printf("b"); // 块设备文件 else if(S_ISFIFO(mode)) printf("p"); // 管道文件 else if(S_ISLNK(mode)) printf("l"); // 链接文件 else printf("s"); // socket文件 } void file_power(const struct stat* file_message) { mode_t mode = file_message->st_mode; printf("%c", mode&S_IRUSR?'r':'-'); printf("%c", mode&S_IWUSR?'w':'-'); printf("%c", mode&S_IXUSR?'x':'-'); printf("%c", mode&S_IRGRP?'r':'-'); printf("%c", mode&S_IWGRP?'w':'-'); printf("%c", mode&S_IXGRP?'x':'-'); printf("%c", mode&S_IROTH?'r':'-'); printf("%c", mode&S_IWOTH?'w':'-'); printf("%c ", mode&S_IXOTH?'x':'-'); }
(3)第三列为文件硬链接个数
printf("%3ld ", file_message->st_nlink); // 打印硬链接数
(4)第四列为文件用户信息
struct passwd* pwd; pwd = getpwuid(file_message->st_uid); printf("%s ",pwd->pw_name);
(5)第五列为文件用户组信息
struct group* grp; grp = getgrgid(file_message->st_gid); printf("%s ",grp->gr_name);
(6)第六列为文件大小
printf("%5ld ", file_message->st_size); // 打印文件大小
(7)第七列为文件上次修改的时间
void file_mtime(const struct stat* file_message) { struct tm* t = localtime(&file_message->st_mtime); printf("%2d月%2d日 %02d:%02d ", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min); // 打印文件上次修改的时间 }
(8)第八列为文件名
printf("%s ", filename); // 打印文件名
3. 通过该实验产生新的疑问及解答
了解了ls -lai
ls -l #以长格式显示目录下的内容列表。输出的信息从左到右依次包括文件名,文件类型、权限模式、硬连接数、所有者、组、文件大小和文件的最后修改时间等 ls -a #显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为隐藏,不会列出) ls -i #显示文件索引节点号(inode number),一个索引节点代表一个文件