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

  

  • 姓名 邹文兵
  • 学号 201821121028
  • 班级 计算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(-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"
    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)
{  
    printf("%d ",(int)file_message->st_ino);//打印索引号
    file_type(file_message); // 打印文件类型
    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':'-');  //执行
}
 

/*转换并打印用户id与组id*/
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. 分析运行

代码运行结果,选取部分文件作为比较:

 

使用ls -lai命令后运行结果:

 

 

 

第1行:总计(total)

Total后面的数字是指当前目录下所有文件所占用的空间总和。可以使用ls –lh查看,也可使用ls –alh查看。

第1字段: 索引节点号inode 

 

 

 实现代码:

printf("%d ",(int)file_message->st_ino);//打印索引号

第2字段: 文件属性字段

文件属性字段总共有10个字母组成;第一个字符代表文件的类型

字母“-”表示该文件是一个普通文件

字母“d”表示该文件是一个目录,字母"d",是dirtectory(目录)的缩写

注意:目录或者是特殊文件,这个特殊文件存放其他文件或目录的相关信息

字母“l”表示该文件是一个链接文件。字母"l"是link(链接)的缩写,类似于windows下的快捷方式

字母“b”的表示块设备文件(block),一般置于/dev目录下,设备文件是普通文件和程序访问硬件设备的入口,是很特殊的文件。没有文件大小,只有一个主设备号和一个辅设备号。一次传输数据为一整块的被称为块设备,如硬盘、光盘等。最小数据传输单位为一个数据块(通常一个数据块的大小为512字节)

字母为“c”表示该文件是一个字符设备文件(character),一般置于/dev目录下,一次传输一个字节的设备被称为字符设备,如键盘、字符终端等,传输数据的最小单位为一个字节。

字母为“p”表示该文件为命令管道文件。与shell编程有关的文件。

字母“s”表示该文件为sock文件。与shell编程有关的文件。 

第1字符的后面9个字母表示该文件或目录的权限位。

r表是读 (Read) 、w表示写 (Write) 、x表示执行 (eXecute)

其中前三个表示文件拥有者的权限,中间三个表示文件所属组拥有的权限,最后三个表示其他用户拥有的权限。 

实现代码:

/*打印文件类型*/
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':'-');  //执行
}

第3字段:文件硬链接数

如果一个文件不是目录,此时这一字段表示这个文件所具有的硬链接数,

第2字段的值为1,说明这个文件只有exit这一个文件名。即只有一个指向该链接的硬链接。。

如果使用ln,做一个指向该文件的硬链接再查看该文件,该文件的第2字段就会变成2

实现代码:

printf("%d ", file_message->st_nlink); // 打印硬链接数

第4字段:文件(目录)拥有者

该字段表示此文件是属于哪个用户。

实现代码:

    struct passwd* pwd;
    pwd = getpwuid(file_message->st_uid);
    printf("%s ",pwd->pw_name);

第5字段:文件(目录)拥有者所在的组

一个用户可以加入很多个组,但是其中有一个是主组

 

 

 实现代码:

    struct group* grp;
    grp = getgrgid(file_message->st_gid);
    printf("%s ",grp->gr_name);

第6字段: 文件所占用的空间(以字节为单位)

第5字段表示文件大小,如果是一个文件夹(目录),则表示该文件夹的大小。是文件夹本身的大小,而不是文件夹以及它下面的文件的总大小。

实现代码:

printf("%5ld ", file_message->st_size); // 打印文件大小

第7字段:文件(目录)最近访问(修改)时间

实现代码:

/*打印文件最近修改时间*/
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);
}

第8字段:文件名

实现代码:

printf("%s ", filename); // 打印文件名
    if(S_ISLNK(file_message->st_mode)) // 如果是软链接文件,打印其指向的位置
        link_printf(filename);
    puts("");
/*打印软连接文件的位置*/
void link_printf(const char* filename)
{
    char buf[1024] = "123";
    if(0 == readlink(filename, buf, sizeof(buf)))
        error_printf("readlink");
    printf("-> %s ",buf);
}

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

产生的问题:无法获得准确的Total后面的数字的当前目录下所有文件所占用的空间总和。

posted @ 2020-04-30 21:24  zouwenbin  阅读(185)  评论(0编辑  收藏  举报