分类: LINUX
2009-10-17 19:44:02
1. 第一个版本还有哪些问题
第一个版本中我们已经实现了ls显示目录下所有文件文件名的功能,但仅限如此。而实际的ls有很多参数选择。我们也不可能全部实现,现在就选一个比较常用的-l参数来实现。
1) 显示文件的详细信息,即加-l选项,效果如下:
struct stat
{
dev_t st_dev; /*文件的设备编号*/
ino_t st_ino; /*文件的i-node*/
mode_t st_mode; /*文件的类型和存取的权限*/
nlink_t st_nlink; /*连到该文件的硬连接数目,刚建立的文件值为1*/
uid_t st_uid; /*文件所有者的用户识别码*/
gid_t st_gid; /*文件所有者的组识别码*/
dev_t st_rdev; /*若此文件为装置设备文件,则为其设备编号 */
off_t st_size; /*文件大小,以字节计算*/
unsigned long st_blksize; /*文件系统的I/O 缓冲区大小 */
unsigned long st_blocks; /*占用文件区块的个数,每一区块大小为512 个字节*/
time_t st_atime; /* 文件最近一次被存取或被执行的时间,一般只有在用mknod、utime、read、write与tructate时改变*/
time_t st_mtime; /* 文件最后一次被修改的时间,一般只有在用mknod、utime和write时才会改变*/
time_t st_ctime; /* i-node最近一次被更改的时间,此参数会在文件所有者、组、权限被更改时更新先前所描述的*/
};
我们可以发现。我们上面想要知道的属性都在这个结构里了。其中如链接数、文件大小是可以直接打印、最后修改时间等可以用ctime转化成字符串;唯一的问题是有些属性我们需要做一些转换。比如模式字段现在保存的是16位的二进制数。我们需要转换成-rw-rw-r—这一类字符串;还有st_uid 保存的是用户的ID。我们需要转换成用户名,组ID st_gid也一样。好了。我们又知道接下来需要做哪些工作了。开如吧
首先将模式字段转换成字符
St_mode是一个16位的二进制数。文件类型和权限被编码在这个数中。如图5-1所示:
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'; /* 3位所有者权限 */
if ( mode & S_IWUSR ) str[2] = 'w';
if ( mode & S_IXUSR ) str[3] = 'x';
if ( mode & S_IRGRP ) str[4] = 'r'; /* 3位同组用户权限 */
if ( mode & S_IWGRP ) str[5] = 'w';
if ( mode & S_IXGRP ) str[6] = 'x';
if ( mode & S_IROTH ) str[7] = 'r'; /* 3位其它用户权限 */
if ( mode & S_IWOTH ) str[8] = 'w';
if ( mode & S_IXOTH ) str[9] = 'x';
}
将用户/组ID转换成字符串
接下来唯一的问题就是将用户/组ID转换成字符串,linux下用户列表文件一般在/etc/passwd中。我们可以先打开这个文件了解一下,如图5-2
struct passwd{
char * pw_name; /*用户账号*/
char * pw_passwd; /*用户密码*/
uid_t pw_uid; /*用户识别码*/
gid_t pw_gid; /*组识别码*/
char * pw_gecos; /*用户全名*/
char * pw_dir; /*家目录*/
char * pw_shell; /* 所使用的shell路径*/
};
所以通过uid可以方便的得到用户名:
char *uid_to_name( uid_t uid )
/*
* returns pointer to username associated with uid, uses getpw()
*/
{
struct passwd *getpwuid(), *pw_ptr;
static char numstr[10];
if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){
sprintf(numstr,'%d', uid);
return numstr;
}
else
return pw_ptr->pw_name ;
}
将组ID转换成字符串
一般组列表文件是/etc/group,其内容和意义如下:
group_name:passwd:GID:user_list
在网络计算系统中。组信息也被保存在NIS中。同获取用户名一样。我们可以用类似的库函数getgrgid。同样用man 3 getgrgid获取帮助手册:
头文件
#include
定义函数 strcut group * getgrgid(gid_t gid);
函数说明 getgrgid()用来依参数gid指定的组识别码逐一搜索组文件,找到时便将该组的数据以group结构返回。
返回值 返回group结构数据,如果返回NULL则表示已无数据,或有错误发生。
struct group{
char *gr_name; /*组名称*/
char *gr_passwd; /* 组密码*/
gid_t gr_gid; /*组识别码*/
char **gr_mem; /*组成员账号*/
}
所以我们可以这样写代码:
#include
char *gid_to_name( gid_t gid )
/*
* returns pointer to group number gid. used getgrgid(3)
*/
{
struct group *getgrgid(), *grp_ptr;
static char numstr[10];
if ( ( grp_ptr = getgrgid(gid) ) == NULL ){
sprintf(numstr,'%d', gid);
return numstr;
}
else
return grp_ptr->gr_name;
}
3. 实现
上面我们已经知道怎么把文件的属性转换成字符串了。现在就实现把他们组合起来。实现ls –l的功能:
因为代码比较长就以文件传上。有兴趣的可以下载
点击此处下载 (文件大小:3K)
效果如下图: