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

  • 袁祎琦
  • 201821121033
  • 计算1812

1. 编写程序

在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai的功能,给出源代码。

ls -l:long,除文件名外,同时将文件或子目录的前线、使用者和大小等信息详细列出。
ls -a:all,显示指定目录下所有文件及其子目录,包含隐藏文件(.filename)。
ls -i:inode,输出文件的i节点的索引信息。

常用宏:

  • S_ISDIR:是否是一个目录
  • S_ISCHR:是否是一个字符设备
  • S_ISBLK:是否是一个块设备

文件权限定义:

  • S_IRUSR:用户读权限
  • S_IWUSR:用户写权限
  • S_IRGRP:用户组读权限
  • S_IWGRP:用户组写权限
  • S_IROTH:其他组都权限
  • S_IWOTH:其他组写权限
  1 /*
  2 osls.c文件
  3 */
  4 #include<stdio.h>
  5 #include<string.h>
  6 #include<sys/types.h>
  7 #include<dirent.h>
  8 #include<sys/stat.h>
  9 #include<grp.h>
 10 #include<pwd.h>
 11 
 12 void do_ls(char []);
 13 void dostat(char *);
 14 void show_file_info(char *, struct stat *);
 15 void mode_to_letters(int mode, char str[]);
 16 char *uid_to_name(uid_t uid);
 17 char *gid_to_name(gid_t gid);
 18 
 19 //主函数 
 20 int main(int argc, char **argv){
 21     if (argc == 1){
 22         do_ls(".");
 23     }    
 24     else{
 25         while (--argc){
 26             printf("%s:\n", *++argv);
 27             do_ls(*argv);//切换到指定目录后再显示该目录的内容
 28         chdir("");//再回到当前工作目录上来 
 29         }
 30     }
 31     return 0;
 32 }
 33 //获取指定路径下的文件名 
 34 void do_ls(char dirname[]){
 35     DIR *dir_ptr;
 36     struct dirent *direntp;
 37     /*
 38         opendir函数用来打开参数name指定的目录
 39         并返回DIR *形态的目录流 
 40     */ 
 41     if ((dir_ptr = opendir(dirname)) == NULL){
 42         fprintf(stderr, "ls2: cannot open %s\n", dirname);
 43         dostat(dirname);//如果不是目录就当作文件来显示其属性 
 44     }
 45     else{
 46         /*
 47             readdir返回参数dir目录的下个目录进入点 
 48         */
 49         while((direntp = readdir(dir_ptr)) != NULL){
 50             dostat(direntp->d_name);//逐个显示目标文件信息 
 51         }
 52         closedir(dir_ptr);
 53     }
 54 }
 55 //文件显示
 56 void dostat(char *filename){
 57     struct stat info;
 58     struct dirent *direntp;
 59     if (stat(filename, &info) == -1){//取文件信息失败 
 60         perror(filename);
 61     }
 62     else{//显示文件信息 
 63         show_file_info(filename, &info);
 64     }
 65 }
 66 //显示指定文件详细信息 
 67 void show_file_info(char *filename, struct stat *info_p){
 68     char *uid_to_name(), *ctime(), *gid_to_name();
 69     void mode_to_letters();
 70     char modestr[11];
 71     struct dirent *direntp;
 72     mode_to_letters(info_p->st_mode, modestr);
 73     
 74     printf("%d", (int)info_p->st_ino); 
 75     printf("%s",modestr);
 76     printf("%4d ",(int)info_p->st_nlink);
 77     printf("%-8s ", uid_to_name(info_p->st_uid));
 78     printf("%-8s ", gid_to_name(info_p->st_gid));
 79     printf("%8ld ", (long)info_p->st_size);
 80     printf("%.12s ", 4 + ctime(&info_p->st_mtime));
 81     printf("%s\n", filename);
 82 }
 83 //显示文件读写权限函数 
 84 void mode_to_letters(int mode, char str[]){
 85     strcpy(str, "-----------");//default=无参数 
 86 
 87     if (S_ISDIR(mode))         str[0] = 'd';//目录 
 88     if (S_ISCHR(mode))         str[0] = 'c';//字符设备 
 89     if (S_ISBLK(mode))         str[0] = 'b';//块设备 
 90 
 91     if (mode & S_IRUSR)        str[1] = 'r';//用户权限 
 92     if (mode & S_IWUSR)        str[2] = 'w';
 93     if (mode & S_IXUSR)        str[3] = 'x';
 94 
 95     if (mode & S_IRGRP)        str[4] = 'r';//组权限 
 96     if (mode & S_IWGRP)        str[5] = 'w';
 97     if (mode & S_IXGRP)        str[6] = 'x';
 98 
 99     if (mode & S_IROTH)        str[7] = 'r';//其他权限 
100     if (mode & S_IWOTH)        str[8] = 'w';
101     if (mode & S_IXOTH)        str[9] = 'x';
102 }
103 char *uid_to_name(uid_t uid){
104     struct passwd * getpwuid(), *pw_ptr;
105     static char numstr[10];
106     //获取用户id 
107     if ((pw_ptr = getpwuid(uid)) == NULL){
108         sprintf(numstr, "%d", uid);
109         return numstr;
110     }
111     else{
112         return pw_ptr->pw_name;
113     }
114 }
115 char *gid_to_name(gid_t gid){
116     struct group *getgrgid(), *grp_ptr;
117     static char numstr[10];
118     //获取组id 
119     if ((grp_ptr = getgrgid(gid)) == NULL){
120         sprintf(numstr, "%d", gid);
121         return numstr;
122     }
123     else{
124         return grp_ptr->gr_name;
125     }
126 }
127 //ls -l:long,除文件名外,同时将文件或子目录的前线、使用者和大小等信息详细列出。
128 //ls -a:all,显示指定目录下所有文件及其子目录,包含隐藏文件(.filename)。
129 //ls -i:inode,输出文件的i节点的索引信息。

2. 分析运行结果

分解命令看不同:

1、

2、

3、

系统自带 ls -lai 命令:

自行编写实现:

运行 ./osls 例子分析:

923827 -rw-r--r-- 1 yuanyiqi jmu-cs-18 3586 Apr 30 19:16 osls.c 

第一字段:文件inode号。

第二字段:r表示读(read),w表示写(write),x表示执行(execute),其表示中前三个表示文件文件属主的权限,中间三个表示组用户权限,最后三个表示其他用户权限。其中yuanyiqi是文件拥有者,jmu-cs-18是组用户。

第三字段:文件硬链接数或者子目录数,上面的例子的第二字段值为1,说明这个文件只有osls一个文件名,即只有一个指向该连接的硬链接。

第四字段:文件属主用户名。

第五字段:文件属主所在的组用户。

第六字段:文件大小。

第七、八、九字段:文件创建具体时间。

最后一个字段:文件名。

3. 通过该实验产生新的疑问及解答

 1、ls-l后显示出的total是什么?怎么计算出来的?

答:total其实就是所有文件所占的块的大小总和,首先数据块(block),Linux的数据存储是以block为单位的,可以理解为一个固定的容器。默认数值是4096,就是4K,由于total的单位是K(1024)。

 ls -l 后:

该功能是依赖命令 ls -s 实现的,如下图:

以下是实现计算total的主要代码部分:

 1 long nTotalBlocks = 0;
 2 DIR* dp = opendir(dirPathName);
 3 struct dirent* dirp;
 4 while ((dirp = readdir(dp)) != NULL) {
 5     lstat(fullPath, &sbuf);
 6     long nBlocks = sbuf.st_size / 4096;
 7     if (sbuf.st_size % 4096 > 0)
 8         nBlocks++;
 9     if (S_ISLNK(sbuf.st_mode))
10         nBlocks = 0;
11     nTotalBlocks += nBlocks;
12 }
13 closedir(dp);
14 cout << "total " << nTotalBlocks * 4 << endl;

 

posted @ 2020-04-30 20:30  DAY--BY--DAY  阅读(231)  评论(0编辑  收藏  举报