1、ls能做什么
ls的默认动作是找到当前目录中所有文件的文件名,按字典序排序后输出,ls -l会列出每个文件的详细信息。所以ls做了一下两件事,第一列出目录的内容,第二显示文件的信息。
自己编写一个ls,一下三点需要掌握:
- 如何列出目录内容
- 如何读取并显示文件属性
- 给一个名字,如何能够判断出它是目录还是文件
2、ls是如何实现的
ls的逻辑和who十分相似,主要区别是who从文件中读数据,而ls从目录中读数据。ls的工作流程:打开目录,读取每个条目,展示文件的信息,关闭目录。
目录是文件的列表,记录的序列,每条记录对应一个文件或子目录。通过readdir来读取目录中的记录,readdir返回一个指向目录的当前记录的指针,记录的类型是struct dirent,这个结构定义在/usr/include/dirent.h中,dirent结构中成员d_name用于存放文件名。
struct dirent:
ino_t d_ino File serial number.
char d_name[] Name of entry.
以上相当于完成了ls的第一件事列出目录内容。ls的第二件事ls -l显示文件的详细信息。ls -l每行总共包含7个字段:
- 模式(mode):文件访问权限,针对3种对象用户、同组用户、其他用户的读、写、执行权限总共九种文件访问权限
- 链接数(links):该文件被引用的次数
- 文件所有者(ower):文件所有者的用户名
- 组(group):文件所有者所在组
- 大小(size):文件的大小
- 最后修改时间(last-modified):文件的最后修改时间
- 文件名(name):文件名
stat、chmod、chown、utime系统调用:
- stat():用于得到文件的属性,result=stat(char *fname,struct stat *bufp),stat把文件fname的信息复制到指针bufp所指的结构中。
- chmod():修改文件的许可权限和特殊属性,result=chmod(char *path,mode_t mode),将文件path的属性修改为mode。
- chown():修改文件所有者和组,result=chown(char *path,uid_t owner,gid_t group),将文件的所有者id改为owner,文件的组id改为group。
- utime():修改文件最后修改时间和最后访问时间,utime(char *path,struct utimebuf *newtime),将文件path的最后修改时间和最后访问时间修改为指向newtime的utimebuf结构体。
通过命令man -k file | grep -i stat查找有关文件状态的系统调用。用stat可以得到文件的信息,通过系统调用stat将文件filename的属性信息存入结构struct stat中去。struct stat的成员变量有:
- st_mode:16位,4位文件类型、3位文件特殊属性、9位文件许可权限,可以通过掩码获取9位文件许可权限
- st_uid:用户所有者的ID,可以通过系统调用getpwuid获取用户所有者的ID对应的用户名
- st_gid:所在组ID,可以通过系统调用getgrgid获取用户所在组的ID对应的组名
- st_size:所占字节数
- st_nlink:文件链接数
- st_mtime:文件最后修改时间
- st_atime:文件最后访问时间
- st_ctime:文件属性最后改变时间
dev_t st_dev Device ID of device containing file.
ino_t st_ino File serial number.
mode_t st_mode Mode of file (see below).
nlink_t st_nlink Number of hard links to the file.
uid_t st_uid User ID of file.
gid_t st_gid Group ID of file.
dev_t st_rdev Device ID (if file is character or block special).
off_t st_size For regular files, the file size in bytes.
For symbolic links, the length in bytes of the
pathname contained in the symbolic link.
For a shared memory object, the length in bytes.
For a typed memory object, the length in bytes.
For other file types, the use of this field is
unspecified.
time_t st_atime Time of last access.
time_t st_mtime Time of last data modification.
time_t st_ctime Time of last status change.
blksize_t st_blksize A file system-specific preferred I/O block size for
this object. In some file system types, this may
vary from file to file.
blkcnt_t st_blocks Number of blocks allocated for this object.
3、自己编写一个ls
ls1.c
#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
void do_ls(char dirname[])
{
DIR *dir_ptr;
struct dirent* direntp;
if((dir_ptr=opendir(dirname))==NULL)
fprintf(stderr,"ls1:cannot open %s\n",dirname);
else
{
while((direntp=readdir(dir_ptr))!=NULL)
printf("%s\n",direntp->d_name);
closedir(dir_ptr);
}
}
int main(int argc,char *argv[])
{
if(argc==1)
do_ls(".");
else
{
while(--argc)
{
printf("%s:\n",*++argv);
do_ls(*argv);
}
}
return 0;
}
ls2.c
#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
#include<sys/stat.h>
void do_ls(char dirname[])
{
DIR *dir_ptr;
struct dirent *direntp;
if((dir_ptr=opendir(dirname))==NULL)
fprintf(stderr,"ls1:cannot open %s\n",dirname);
else
{
while((direntp=readdir(dir_ptr))!=NULL)
dostat(direntp->d_name);
closedir(dir_ptr);
}
}
void dostat(char *filename)
{
struct stat info;
if(stat(filename,&info)==-1)
perror(filename);
else
show_file_info(filename,&info);
}
void show_file_info(char *filename,struct stat *info_p)
{
char *uid_to_name(),*gid_to_name(),*ctime(),*filemode(); //先声明两个函数
char modestr[11];
mode_to_letters(info_p->st_mode,modestr);
printf("%s",modestr);
printf("%4d ",(int)info_p->st_nlink);
printf("%-8s ",uid_to_name(info_p->st_uid));
printf("%-8s ",gid_to_name(info_p->st_gid));
printf("%8ld ",(long)info_p->st_size);
printf("%.12s ",4+ctime(&info_p->st_mtime));
printf("%s\n",filename);
}
void mode_to_letters(int mode,char str[])
{
strcpy(str,"----------");
if(S_ISDIR(mode)) str[0]='d';
if(S_ISCHR(mode)) str[0]='c';
if(S_ISBLK(mode)) str[0]='b';
if(mode&S_IRUSR) str[1]='r';
if(mode&S_IWUSR) str[2]='w';
if(mode&S_IXUSR) str[3]='x';
if(mode&S_IRGRP) str[4]='r';
if(mode&S_IWGRP) str[5]='w';
if(mode&S_IXGRP) str[6]='x';
if(mode&S_IROTH) str[7]='r';
if(mode&S_IWOTH) str[8]='w';
if(mode&S_IXOTH) str[9]='x';
}
#include<pwd.h>
char *uid_to_name(uid_t uid)
{
struct passwd *pw_ptr;
static char numstr[10];
if((pw_ptr=getpwuid(uid))==NULL)
{
sprintf(numstr,"%d",uid);
return numstr;
}
else
return pw_ptr->pw_name;
}
#include<grp.h>
char *gid_to_name(gid_t gid)
{
struct group *grp_ptr;
static char numstr[10];
if((grp_ptr=getgrgid(gid))==NULL)
{
sprintf(numstr,"%d",gid);
return numstr;
}
else
return grp_ptr->gr_name;
}
int main(int argc,char *argv[])
{
if(argc==1)
do_ls(".");
else
{
while(--argc)
{
printf("%s:\n",*++argv);
do_ls(*argv);
}
}
return 0;
}