第3章 目录与文件属性:编写ls

1.ls常见用法

第3章 目录与文件属性:编写ls

ls做了两件事情:一是列出目录内容,二是显示文件信息

2.ls工作原理

第3章 目录与文件属性:编写ls

每个目录至少包含两个特殊 的项,“.”当前目录和“..“上一级目录

读取目录需要用到三个函数opendir,readdir,closedir

第3章 目录与文件属性:编写ls

目录结构体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的输出

第3章 目录与文件属性:编写ls

Linux的文件种类有7中:

1.普通文件(regular file)[ - ]

2.目录(directory) [ d ] 

3.连接文件(link)[ l ]

4.设备和设备文件

  快设备文件,即一些存储文件,如硬盘、软盘等,[ b ]

  字符设备文件,即一些串行端口的接口文件,如键盘、鼠标等,[ c ]

5.套接字(sockets)[ s ]

6.管道(FIFO,pipe)[ p ]

提取文件状态函数stat

第3章 目录与文件属性:编写ls

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位的二进制数,文件类型和权限被编码在这个数中

第3章 目录与文件属性:编写ls

前四位是文件类型,可以标识16种类型,目前只用了7种。接下来的3位是set-user-ID位、set-group-ID位和sticky位,1代表具有某个属性,0代表没有。最后9位是许可权限。

文件类型在模式字段的前四位,可以通过掩码来将其他的部分置0,从而得到类型的值。

第3章 目录与文件属性:编写ls

也可以通过下面的宏来判断文件类型

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改变文件模式

第3章 目录与文件属性:编写ls

 

修改文件所有者和所有组chown

第3章 目录与文件属性:编写ls

修改文件最后修改时间和最后访问时间

第3章 目录与文件属性:编写ls