操作系统第4次实验报告:文件系统
2020-04-30 18:00 Wangpj 阅读(163) 评论(0) 编辑 收藏 举报姓名:王丕杰
班级:计算1812
学号:201821121052
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。
*/
}
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. 分析运行结果
运行 ls -lai 语句,运行结果如下:
分析结果如下:
(1)第一列为文件索引号
printf("%d ",(int)file_message->st_ino);//添加索引号
(2)第二列首字母为文件类型,后面的 “r” 、“w”、“x”为读、写、执行的权限。
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)第三列为文件硬链接个数
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)第六列为文件大小
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); // 打印文件名