操作系统第4次实验报告:文件系统
- 林伟强
- 201821121010
- 计算1811
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<time.h> #include<pwd.h> #include<grp.h> void error_printf(const char* ); void list_dir(const char* ); void list_message(const char* , const struct stat*); void file_type(const struct stat* ); void file_power(const struct stat* ); void file_id(const struct stat* ); void file_mtime(const struct stat* ); void link_printf(const char* ); void error_printf(const char* funname) { perror(funname); exit(EXIT_FAILURE); /* * EXIT_SUCCESS和EXIT_FAILURE是两个常量。 * EXIT_SUCCESS=0,EXIT_FAILURE=1。 * 0表示程序寿终正寝,1表示死于非命。 */ } void list_dir(const char* pathname) { DIR* ret_opendir = opendir(pathname); // 打开目录"pathname" if(ret_opendir == NULL) error_printf("opendir"); int ret_chdir = chdir(pathname); // 改变工作目录至"pathname",便于stat函数的使用 if(ret_chdir == -1) error_printf("chdir"); struct dirent* ret_readdir = NULL; // 定义readdir函数返回的结构体变量 while(ret_readdir = readdir(ret_opendir)) // 判断是否读取到目录尾 { char* filename = ret_readdir->d_name; // 获取文件名 struct stat file_message = {}; // 定义stat函数返回的结构体变量 int ret_stat = lstat(filename, &file_message); // 获取文件信息 if(ret_stat == -1) // stat读取文件错误则输出提示信息 printf("%s error!", filename); else if(strcmp(filename,".") && strcmp(filename,"..")) // 不输出当前目录与上一级目录 list_message(filename, &file_message); } } void list_message(const char* filename, const struct stat* file_message) { file_type(file_message); // 判断打印文件类型 printf("%d ",(int)file_message->st_ino);//添加索引号 file_power(file_message); // 判断并打印文件权限 printf("%d ", file_message->st_nlink); // 打印硬链接数 file_id(file_message); // 转换并打印用户id与组id printf("%5ld ", file_message->st_size); // 打印文件大小 file_mtime(file_message); // 打印文件最后修改时间 printf("%s ", filename); // 打印文件名 if(S_ISLNK(file_message->st_mode)) // 如果是软链接文件,打印其指向的位置 link_printf(filename); puts(""); } 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':'-'); } void file_id(const struct stat* file_message) { struct passwd* pwd; pwd = getpwuid(file_message->st_uid); printf("%s ",pwd->pw_name); struct group* grp; grp = getgrgid(file_message->st_gid); printf("%s ",grp->gr_name); } 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); } void link_printf(const char* filename) { char buf[1024] = "123"; if(0 == readlink(filename, buf, sizeof(buf))) error_printf("readlink"); printf("-> %s ",buf); }
int main()
{ char path[1024] = {};
strcpy(path,"./");
struct stat file_message = {};
int ret_stat = lstat(path, &file_message);
if(ret_stat == -1)
error_printf("stat");
if(S_ISDIR(file_message.st_mode)) // 判断是否为目录
list_dir(path);
else
list_message(path, &file_message);
return 0;
}
2. 分析运行结果
给出运行结果截图,对于每一列是如何获取的,结合源代码做解释
suqiankun@jmu-cs-ubuntu:~$ ls -lai
total 160
920635 drwx------ 6 suqiankun ubuntu 4096 Apr 27 09:52 .
131195 drwxr-xr-x 129 root root 4096 Apr 25 21:52 ..
920658 -rw------- 1 suqiankun ubuntu 10359 Apr 27 10:38 .bash_history
920636 -rw-r--r-- 1 suqiankun ubuntu 220 Apr 5 2018 .bash_logout
920638 -rw-r--r-- 1 suqiankun ubuntu 3771 Apr 5 2018 .bashrc
920656 drwx------ 2 suqiankun ubuntu 4096 Mar 11 16:01 .cache
第一列为索引号
第二列
drwxr-xr-x代表文件的类型及权限
以d开头的为文件夹,以-开头的为文件,
以l开头的为连接文件
第三列:文件的链接数.
第四列:拥有文件的用户
第五列:拥有文件的组
第六列:文件的大小。
第七列:文件最后的修改时间。
第八列:文件名
以上图一为实验代码所得 图二为ls -lai
添加索引号
printf("%d ",(int)file_message->st_ino);//添加索引号
第二列
drwxr-xr-x代表文件的类型及权限
以d开头的为文件夹,以-开头的为文件,
以l开头的为连接文件
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':'-');
}
第三列:文件的链接数.
printf("%d ", file_message->st_nlink); // 打印硬链接数
第四列:拥有文件的用户
struct passwd* pwd;
pwd = getpwuid(file_message->st_uid);
printf("%s ",pwd->pw_name);
第五列:拥有文件的组
struct group* grp;
grp = getgrgid(file_message->st_gid);
printf("%s ",grp->gr_name);
第六列:文件的大小。
printf("%5ld ", file_message->st_size); // 打印文件大小
第七列:文件最后的修改时间。
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);
}
第八列:文件名
printf("%s ", filename); // 打印文件名
3. 通过该实验产生新的疑问及解答
实验中文件最后修改时间和文件类型和权限是实验中最困难的地方