操作系统第4次实验报告:文件系统

零、个人信息

  • 姓名:陈韵
  • 学号:201821121053
  • 班级:计算1812

一、编写程序

  ls -lai实现要求:

  • ls -l :长数据串行出,包含文件的属性与权限等等数据.
  • ls -a:全部的文件,连同隐藏文件( 开头为 . 的文件) 一起列出来.
  • ls -i :列出 inode 号码.
  • ls用于列举工作目录下的内容,需要打开该目录建立目录流读取文件,使用结构体:DIR、dirent。
  • 涉及到文件信息的获取,需要利用与文件相关的结构体:stat。

  大致思路:

  1. 获取当前的工作目录路径,打开目录DIR同时建立目录流dirent用以不断读取目录内文件。
  2. 以每一个文件为一行格式化输出其属性: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-  -权限-    -链接- -拥有者-  -群组-     -文件大小-  -修改日期-  -文件名-

  • 文件类型:
  1. 普通文件
  2. 目录文件
  3. 块特殊文件
  4. 字符特殊文件
  5. FIFO
  6. 套接字
  7. 符号链接
  • 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个时间字段。他们分别是:

 

 

posted @ 2020-04-30 20:08  韵韵韵  阅读(337)  评论(0编辑  收藏  举报