操作系统第4次实验报告:文件系统
零、个人信息
- 姓名:陈韵
- 学号:201821121053
- 班级:计算1812
一、编写程序
ls -lai实现要求:
- ls -l :长数据串行出,包含文件的属性与权限等等数据.
- ls -a:全部的文件,连同隐藏文件( 开头为 . 的文件) 一起列出来.
- ls -i :列出 inode 号码.
- ls用于列举工作目录下的内容,需要打开该目录建立目录流读取文件,使用结构体:DIR、dirent。
- 涉及到文件信息的获取,需要利用与文件相关的结构体:stat。
大致思路:
- 获取当前的工作目录路径,打开目录DIR同时建立目录流dirent用以不断读取目录内文件。
- 以每一个文件为一行格式化输出其属性:1.inode 2.类型权限 3.连接数 4.拥有者 5.所属群组 6.容量大小 7.最后被修改的时间 8.文件名.
实现源码如下:
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 int opt = 0; //参数 15 //--------- 16 /*-------------12345678表示格式化输出对应的列 ------*/ 17 //获得对应参数 18 void getParameter(int argc, char *argv[], char *path) 19 { 20 int i = 0; 21 for (i = 1; i < argc; ++i) 22 { 23 //参数必须以-开头。没有则退出 24 if (strncmp(argv[i], "-", 1) == 0) 25 { 26 //根据参数把不同的值送入不同的位置中,利用或运算实现多个参数 27 //参数为a时 28 if (strstr(argv[i], "a") != NULL) 29 { 30 opt |= 1 << 0; 31 } 32 //参数为l 33 if (strstr(argv[i], "l") != NULL) 34 { 35 opt |= 1 << 1; 36 } 37 //参数为i 38 if (strstr(argv[i], "i") != NULL) 39 { 40 opt |= 1 << 2; 41 } 42 } 43 else 44 { 45 printf("参数输入错误,退出!!!!"); 46 exit(0); 47 } 48 } 49 } 50 //输出结果格式化 51 void PrintLS(int mode, struct stat st) 52 { 53 //2.输出文件对 拥有者、群组、其他用户的权限。 54 //10个字符,1位文件类型,234拥有者权限,567群组权限,89 10其他用户权限 55 char authority[11] = {"----------"}; 56 //第一位 57 if (S_ISDIR(mode)) 58 authority[0] = 'd'; 59 if (S_ISCHR(mode)) 60 authority[0] = 'c'; 61 if (S_ISBLK(mode)) 62 authority[0] = 'b'; 63 //拥有者权限 64 if (mode & S_IRUSR) 65 authority[1] = 'r'; 66 if (mode & S_IWUSR) 67 authority[2] = 'w'; 68 if (mode & S_IXUSR) 69 authority[3] = 'x'; 70 //群组权限 71 if (mode & S_IRGRP) 72 authority[4] = 'r'; 73 if (mode & S_IWGRP) 74 authority[5] = 'w'; 75 if (mode & S_IXGRP) 76 authority[6] = 'x'; 77 //其他用户权限 78 if (mode & S_IROTH) 79 authority[7] = 'r'; 80 if (mode & S_IWOTH) 81 authority[8] = 'w'; 82 if (mode & S_IXOTH) 83 authority[9] = 'x'; 84 85 //输出权限 86 for (int i = 0; i < 10; i++) 87 { 88 printf("%c", authority[i]); 89 } 90 //3.输出连接数 91 printf("%ld ", st.st_nlink); 92 93 //4.输出拥有者 94 struct passwd *pd = getpwuid(st.st_uid); 95 assert(pd != NULL); 96 printf("%5s ", pd->pw_name); 97 98 //5.输出所属群组 99 struct group *gp = getgrgid(st.st_gid); 100 assert(gp != NULL); 101 printf("%5s ", gp->gr_name); 102 103 //6.输出文件的大小 104 printf("%-5ld ", st.st_size); 105 106 //7.输出文件最近被修改的时间 107 struct tm *changeTime = localtime(&(st.st_mtime)); 108 printf("%d %d %d:%d ", (changeTime->tm_mon + 1), changeTime->tm_mday, changeTime->tm_hour, changeTime->tm_min); 109 } 110 //8.输出文件名。并对文件名的颜色进行渲染。 111 void PrintfFileName(int mode, int uid, char *name) 112 { 113 //目录===>把文件名显示为蓝色。 114 if (S_ISDIR(mode)) 115 { 116 117 printf("\33[1;34m%s\033[0m ", name); 118 } 119 //普通文件 120 else if (S_ISREG(mode)) 121 { 122 if (mode & S_IXUSR || mode & S_IXGRP || mode & S_IXOTH) 123 { 124 //主用户,显示为红色。 125 if (uid == 0) 126 printf("\33[41;37m%s\033[0m ", name); 127 //其他用户,显示为绿色 128 else 129 printf("\33[1;32m%s\033[0m ", name); 130 } 131 //不需要渲染,直接输出文件名 132 else 133 printf("%s ", name); 134 } 135 //不需要渲染,直接输出文件名 136 else 137 printf("%s ", name); 138 } 139 140 int main(int argc, char *argv[]) 141 { 142 char path[128] = {0}; 143 getcwd(path, 127); //获取文件路径 144 getParameter(argc, argv, path); //识别对应的参数 145 146 //打开该目录并建立一个目录流 147 DIR *dir = opendir(path); 148 if (dir == NULL) 149 { 150 char *p = path + strlen(path); 151 while (*p != '/') 152 p--; 153 p++; 154 printf("ls不能访问%s !!!!!!!\n", p); 155 exit(0); 156 } 157 158 struct dirent *dr = NULL; 159 //从目录流读入所有的文件 160 while ((dr = readdir(dir)) != NULL) 161 { 162 //跳过以.开头的隐藏文件,不输出 163 if (((opt & 1) == 0) && (strncmp(dr->d_name, ".", 1) == 0)) 164 continue; 165 166 struct stat st; 167 char temp[128] = {0}; 168 strcpy(temp, path); 169 strcat(temp, "/"); 170 strcat(temp, dr->d_name); 171 stat(temp, &st); 172 //当输入了 -lai。 173 if ((opt & 2) == 2) 174 { 175 176 if ((opt & 4) == 4) //转成二进制运算 177 { 178 printf("%ld ", st.st_ino); //-i 179 } 180 PrintLS(st.st_mode, st); //-l 181 PrintfFileName(st.st_mode, st.st_uid, dr->d_name); //-a 182 printf("\n"); 183 } 184 } 185 //读取完毕换行 186 if (argc == 1 || (argc > 1 && opt == 0)) 187 printf("\n"); 188 189 //关闭文件流 190 closedir(dir); 191 }
二、分析运行结果
1.先进行ls -lai 以便对程序结果有个对照:
2.编译程序后得到的结果:
3.分析结果的属性&结合源码:
(1)inode编号:
利用stat结构体
(2)文件类型权限:
(3)文件连接数
利用stat结构体:
(4)文件拥有者 利用stat结构体获取uid
(5)文件所属群组 利用stat结构体获取gid
(6)文件容量大小 利用stat结构体获取size
(7)文件最后修改时间 利用stat结构体获取mtime
(8)文件名 这里需要根据目录还是文件显示不同的颜色。利用dirent结构体获取name。
4.小结:
- linux文件类型权限示意图:
- linux文件属性:
-inode- -权限- -链接- -拥有者- -群组- -文件大小- -修改日期- -文件名-
- 文件类型:
- 普通文件
- 目录文件
- 块特殊文件
- 字符特殊文件
- FIFO
- 套接字
- 符号链接
- stat结构体:
1 struct stat 2 { 3 dev_t st_dev; /* ID of device containing file -文件所在设备的ID*/ 4 ino_t st_ino; /* inode number -inode节点号*/ 5 mode_t st_mode; /* protection -保护模式?*/ 6 nlink_t st_nlink; /* number of hard links -链向此文件的连接数(硬连接)*/ 7 uid_t st_uid; /* user ID of owner -user id*/ 8 gid_t st_gid; /* group ID of owner - group id*/ 9 dev_t st_rdev; /* device ID (if special file) -设备号,针对设备文件*/ 10 off_t st_size; /* total size, in bytes -文件大小,字节为单位*/ 11 blksize_t st_blksize; /* blocksize for filesystem I/O -系统块的大小*/ 12 blkcnt_t st_blocks; /* number of blocks allocated -文件所占块数*/ 13 time_t st_atime; /* time of last access -最近存取时间*/ 14 time_t st_mtime; /* time of last modification -最近修改时间*/ 15 time_t st_ctime; /* time of last status change - */ 16 };
- dirent结构体:
- 不仅指向目录,还指向目录中的具体文件。
1 struct dirent 2 { 3 long d_ino; /* inode number 索引节点号 */ 4 5 off_t d_off; /* offset to this dirent 在目录文件中的偏移 */ 6 7 unsigned short d_reclen; /* length of this d_name 文件名长 */ 8 9 unsigned char d_type; /* the type of d_name 文件类型 */ 10 11 char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */ 12 }
三、通过该实验产生新的疑问及解答
- 文件类型包含在哪? 我该怎么确定我读取到的是什么文件?
文件类型的信息包含在stat结构的st_mode成员中。我们可以根据宏来确定文件的类型,如下图所示。
- 文件的时间可以从stat结构体中得到哪些信息?
每个文件都有其维护的3个时间字段。他们分别是: