一、实现要求
又到了期末的时候,Linux实践课的老师挺厚道,布置了算是一个入门的大作业:实现一个简单版本的ls命令。根据Linux技术与实践课程学习的基础知识,编写一个可以在Unix/Linux环境下运行的程序:ls2.c,功能类似于系统自带的ls命令。可以显示特定目录下的所有文件的属性信息,或者直接列出所有文件。
感觉自己写的代码有点乱,但是功能都实现了,这点还不错。目录下的文件多了会发生段错误,不懂为啥,C语言就是这么那啥。再说吧~
具体要求如下:
- 不加 –l 参数,如“ls2 /home”,可以直接列出目录下所有的文件,并按照升序显示。显示在终端里有格式的缩进,即分栏处理。
- 加 –l 参数时,如“ls2 –l /home ”,会详细显示所有的文件信息,与 ls –l 的系统命令基本一致。每行显示一个文件或者文件夹的信息,属性依次是:文件类型,当前用户权限,当前用户组权限,其他用户权限,用户名,组名,链接数,文件大小(字节),修改的最后时间。
- 注意格式化输出,对齐。
- 所有的隐藏文件都不显示。
二、背景讲解
先要讲两个头文件:<dirent.h> 和 <sys/stat.h> ,都是 POSIX.1标准定义的unix类的头文件。
1. <dirent.h>
第一个,dirent.h,是用来处理目录,包含了许多UNIX系统服务的函数原型,例如opendir函数、readdir函数.这里我们可以用来通过文件名打开,关闭,读取特定的文件夹信息,或者说,该目录的信息。可以参考ls_header.h的34开始的代码。
/*
opendir函数可以按照文件名打开一个文件,
并返回一个DIR型的指针,若是返回NULL则说明文件打开失败。
*/
DIR *opendir(const char *pathname);
/*
根据上面的DIR指针,我们可以读取这个目录,readdir会返回一个dirent的结构体指针。
如果不为NULL,说明下面还有文件,可以继续调用readdir来获取下一个文件。
我们可以用得到的dirent结构体指针,获取文件的一些信息。
*/
struct dirent *readdir(DIR *dp);
/* 关闭文件目录 */
int closedir(DIR *dirp);
dirent结构体组成如下,不过这里只用到了d_name,其他的暂时没啥用。
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name 文件名,最长256字符 */
}
2. <sys/stat.h>
这个头文件里面提供一些有用的东西,能根据全路径的文件名获得一个文件(文件夹在Linux中也算是一个特殊的文件,也有各种读写执行的权限)。里面有用的是stat函数,可以传进去一个pathname,结果会保存在一个stat结构体,即buf中,如下:
int stat(const char *restrict pathname,struct stat *restrict buf);
stat结构体可以得到很多关于这个文件的属性信息,也就是我们这里要用 ls 命令列举出来的信息。当然啦,还要转换一下才有可读性。ls_util里面的函数主要就是用来转换成我们要的字符串的。
结构如下:
struct stat{
mode_t st_mode; //文件类型和权限信息
ino_t st_ino; //i结点标识
dev_t st_dev; //device number (file system)
dev_t st_rdev; //device number for special files
nlink_t st_nlink; //符号链接数
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
off_t st_size; //size in bytes,for regular files
time_t st_st_atime; //最后一次访问的时间
time_t st_mtime; //文件内容最后一次被更改的时间
time_t st_ctime; //文件结构最后一次被更改的时间
bl