OS第4次实验报告:文件系统
- 姓名:巫艳珍
- 学号:201821121034
- 班级:计算1812
1. 编写程序
在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai
的功能,给出源代码。
源代码:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<dirent.h> #include<sys/stat.h> #include<sys/types.h> #include<fcntl.h> #include<pwd.h> #include<grp.h> #include<time.h> void filedir(const char* );//打开目录 void file_type(const struct stat* );//文件类型 void file_power(const struct stat* );//文件权限 void file_id(const struct stat* );//文件用户id与组id void print_fileinfo(const char* , const struct stat*);//打印文件信息 void linkprint(const char* ); //打开文件目录 void filedir(const char* dir) { DIR* pdir = opendir(dir); struct dirent* pd = NULL; int ret_chdir = chdir(dir); if(pdir == NULL){ printf("open dir error!\n"); exit(1); } while(pd = readdir(pdir)) // 判断是否读取到目录尾 { char* name = pd->d_name; // 获取文件名 struct stat file = {}; // 定义结构体变量 int buf = lstat(name, &file); // 获取文件信息 if(buf == -1) // 读取文件错误 printf("%s error!", name); else if(strcmp(name,".") && strcmp(name,"..")) // 不输出当前目录与上一级目录 print_fileinfo(name, &file); } } //判断并打印文件类型 void file_type(const struct stat* file) { mode_t mode = file->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) { mode_t mode = file->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':'-'); } //文件用户id与组id void file_id(const struct stat* file) { struct passwd* pwd; pwd = getpwuid(file->st_uid); printf("%s ",pwd->pw_name); struct group* grp; grp = getgrgid(file->st_gid); printf("%s ",grp->gr_name); } void print_fileinfo(const char* name, const struct stat* file) { file_type(file); // 文件类型 printf("%ld ",(int)file->st_ino);//添加索引号 file_power(file); // 打印文件权限 printf("%d ", file->st_nlink); // 硬链接数 file_id(file); //用户id与组id printf("%5ld ", file->st_size); // 打印文件大小 ctime_r(&file.st_mtime,buf); //上一次被修改的时间 buf[16] ='\0'; printf("%s ", buf); printf("%s ", name); // 打印文件名 if(S_ISLNK(file->st_mode)) linkprint(name); puts(""); } void linkprint(const char* name) { char buf[512] = "123"; if(0 == readlink(name, buf, sizeof(buf))) perror("readlink"); printf("-> %s ",buf); } int main() { char dir[512] = {}; strcpy(dir,"./"); struct stat file = {}; if(lstat(dir, &file) == -1)//文件属性 perror("stat"); exit(EXIT_FAILURE); if(S_ISDIR(file.st_mode)) filedir(dir); else print_fileinfo(dir, &file); return 0; }
2. 分析运行结果
给出运行结果截图,对于每一列是如何获取的,结合源代码做解释
对比命令ls -lai:
- 索引号:
printf("%ld ",(int)file->st_ino);//添加索引号
- 文件权限:在打印文件信息时调用file_power函数来打印文件权限:
void file_power(const struct stat* file) { mode_t mode = file->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':'-'); }
- 硬链接数
若一个 inode 号对应多个文件名,则称这些文件为硬链接,硬链接就是同一个文件使用了多个别名。
实现代码:
printf("%d ", file->st_nlink); // 硬链接数
- 用户id与组id:调用函数
file_id(file);
struct passwd* pwd;
pwd = getpwuid(file->st_uid);
printf("%s ",pwd->pw_name);
struct group* grp;
grp = getgrgid(file->st_gid);
printf("%s ",grp->gr_name);
这里用到两个结构体,分别如下:
(1)struct passwd:
#include <sys/types.h> #include <pwd.h> struct passwd { char *pw_name; /* 用户登录名 */ char *pw_passwd; /* 密码(加密后) */ __uid_t pw_uid; /* 用户ID */ __gid_t pw_gid; /* 组ID */ char *pw_gecos; /* 详细用户名 */ char *pw_dir; /* 用户目录 */ char *pw_shell; /* Shell程序名 */ };
(2)struct group:
#include <sys/types.h> #include <grp.h> struct group { char *gr_name; /* 组名 */ char *gr_passwd; /* 密码 */ __gid_t gr_gid; /* 组ID */ char **gr_mem; /* 组成员名单 */ }
- 打印文件大小(即文件占用的空间):
printf("%5ld ", file->st_size); // 打印文件大小
- 上一次被修改的时间:
ctime_r(&file.st_mtime,buf); //上一次被修改的时间 buf[16] ='\0'; printf("%s ", buf);
与文件时间有关的三个方面的管理属性:
stat.st_atime(数据的最后访问时间)、stat.st_mtime(数据的最后修改时间)、stat.st_ctime(i节点最后更改时间)
- 文件名:
printf("%s ", name); // 打印文件名
3. 通过该实验产生新的疑问及解答
疑问1:索引号的打印与ls -lai的命令不同,但total的算法还未找到解决方法
疑问2:获得文件上一次修改的时间有没有其他的写法
解答:可以定义一个结构体,struct time* T = localtime(&file->st_mtime);再利用链表形式打印出来。