第3章 目录与文件属性:编写ls
1.ls常见用法
ls做了两件事情:一是列出目录内容,二是显示文件信息
2.ls工作原理
每个目录至少包含两个特殊 的项,“.”当前目录和“..“上一级目录
读取目录需要用到三个函数opendir,readdir,closedir
目录结构体struct dirent是
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
ls代码
/** ls1.c
** purpose list contents of directory or directories
** action if no args, use . else list files in args
**/
#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
void do_ls(char []);
main(int ac, char *av[])
{
if ( ac == 1 )
do_ls( "." );
else
while ( --ac ){
printf("%s:\n", *++av );
do_ls( *av );
}
}
void do_ls( char dirname[] )
/*
* list files in directory called dirname
*/
{
DIR *dir_ptr; /* the directory */
struct dirent *direntp; /* each entry */
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);
}
}
3.编写ls -l
ls -l的输出
Linux的文件种类有7中:
1.普通文件(regular file)[ - ]
2.目录(directory) [ d ]
3.连接文件(link)[ l ]
4.设备和设备文件
快设备文件,即一些存储文件,如硬盘、软盘等,[ b ]
字符设备文件,即一些串行端口的接口文件,如键盘、鼠标等,[ c ]
5.套接字(sockets)[ s ]
6.管道(FIFO,pipe)[ p ]
提取文件状态函数stat
stat的数据结构
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
st_mode是一个16位的二进制数,文件类型和权限被编码在这个数中
前四位是文件类型,可以标识16种类型,目前只用了7种。接下来的3位是set-user-ID位、set-group-ID位和sticky位,1代表具有某个属性,0代表没有。最后9位是许可权限。
文件类型在模式字段的前四位,可以通过掩码来将其他的部分置0,从而得到类型的值。
也可以通过下面的宏来判断文件类型
The following POSIX macros are defined to check the file type using the st_mode field:
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
将用户/组ID转化成字符串
/etc/passwd文件包含用户列表
每一行代表一个用户,用冒号分成不同的段,第一个字段是用户名,第二个是密码,第三个是用户ID,第四个是用户所属的组,接下来是用户全名、主目录、用户使用的shell程序的路径。
通过库函数getpwuid来访问用户信息,如果用户信息在/etc/passwd中,那么getpwuid会在里面查找;如果用户信息在NIS中,getpwuid会从NIS中获取信息。
The passwd structure is defined in <pwd.h> as follows:
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
getpwuid(uid)->pw_name;
/etc/group组的列表
第一个字段是组名,第二个是密码,第三个是组ID,第四个是组中的成员列表。
通过getgrgid可以得到数组名getgrgid(gid)->gr_name。
/* ls2.c
* purpose list contents of directory or directories
* action if no args, use . else list files in args
* note uses stat and pwd.h and grp.h
* BUG: try ls2 /tmp
*/
#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
#include<sys/stat.h>
#include<pwd.h>
#include<string.h>
void do_ls(char[]);
void dostat(char *);
void show_file_info( char *, struct stat *);
void mode_to_letters( int , char [] );
char *uid_to_name( uid_t );
char *gid_to_name( gid_t );
main(int ac, char *av[])
{
if ( ac == 1 )
do_ls( "." );
else
while ( --ac ){
printf("%s:\n", *++av );
do_ls( *av );
}
}
void do_ls( char dirname[] )
/*
* list files in directory called dirname
*/
{
DIR *dir_ptr; /* the directory */
struct dirent *direntp; /* each entry */
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 ) /* cannot stat */
perror( filename ); /* say why */
else /* else show info */
show_file_info( filename, &info );
}
void show_file_info( char *filename, struct stat *info_p )
/*
* display the info about 'filename'. The info is stored in struct at *info_p
*/
{
char *uid_to_name(), *ctime(), *gid_to_name(), *filemode();
void mode_to_letters();
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 );
}
/*
* utility functions
*/
/*
* This function takes a mode value and a char array
* and puts into the char array the file type and the
* nine letters that correspond to the bits in mode.
* NOTE: It does not code setuid, setgid, and sticky
* codes
*/
void mode_to_letters( int mode, char str[] )
{
strcpy( str, "----------" ); /* default=no perms */
if ( S_ISDIR(mode) ) str[0] = 'd'; /* directory? */
if ( S_ISCHR(mode) ) str[0] = 'c'; /* char devices */
if ( S_ISBLK(mode) ) str[0] = 'b'; /* block device */
if ( mode & S_IRUSR ) str[1] = 'r'; /* 3 bits for user */
if ( mode & S_IWUSR ) str[2] = 'w';
if ( mode & S_IXUSR ) str[3] = 'x';
if ( mode & S_IRGRP ) str[4] = 'r'; /* 3 bits for group */
if ( mode & S_IWGRP ) str[5] = 'w';
if ( mode & S_IXGRP ) str[6] = 'x';
if ( mode & S_IROTH ) str[7] = 'r'; /* 3 bits for other */
if ( mode & S_IWOTH ) str[8] = 'w';
if ( mode & S_IXOTH ) str[9] = 'x';
}
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 ;
}
#include <grp.h>
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;
}
4.st_mode的三个特殊位
1.set-usr-ID位
/etc/passwd问件只有root才有权限更改,passwd命令所有者是root,它包含SUID位,运行这个程序的时候认为是由文件所有者在运行,即root。SUID位经常用来给某些程序提供额外的权限,比如系统中的打印队列。
通过S_ISUID来检测某一个程序是否有SUID位
2.set-group-ID位
如果一个程序的所属的组为g,它的SGID位也被设置,那么运行程序的时候就好像它正被g组中的某一个用户运行一样。
3.sticky位
sticky位使得目录里的文件只能被创建者删除。
小结:目录是特殊的文件,他的内容就是其中的文件和子目录的名字,还包括自己的名字。
5.设置和修改文件的属性
创建文件的许可位 fd = creat(“newfile”,0744);
系统默认新建文件掩码设置 umask(022)
文件链接数link和unlink
chmod改变文件模式
修改文件所有者和所有组chown
修改文件最后修改时间和最后访问时间