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);再利用链表形式打印出来。

posted @ 2020-04-30 19:42  王尔  阅读(201)  评论(0编辑  收藏  举报