linux系统编程:自己动手写一个ls命令

ls用于列举目录内容,要实现这个功能,毫无疑问,需要读取目录,涉及到两个api:

opendir:DIR *opendir(const char *name), 传文件名,返回一个指针,指向目录序列

readdir:struct dirent *readdir(DIR *dirp), 把opendir的返回值传过来,   返回值为一个结构体

        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 */
           };

有了这两个api,就可以实现一个简易的ls功能

 1 /*================================================================
 2 *   Copyright (C) 2018 . All rights reserved.
 3 *   
 4 *   文件名称:myls.c
 5 *   创 建 者:ghostwu(吴华)
 6 *   创建日期:2018年01月09日
 7 *   描    述: ls命令
 8 *
 9 ================================================================*/
10 
11 #include 
12 #include 
13 #include 
14 #include 
15 
16 void do_ls( char [] );
17 
18 int main(int argc, char *argv[])
19 {
20     if( argc == 1 ) {
21         do_ls( "." );
22     }else {
23         while( --argc ) {
24             printf( "arg=%s\n", * ++argv );
25             do_ls( *argv );
26         }
27     }
28     return 0;
29 }
30 
31 void do_ls( char dir_entry[] ) {
32     DIR* pDir;
33     struct dirent* pCurDir;
34     if( ( pDir = opendir( dir_entry ) ) == NULL ){
35         perror( "read dir" );
36         exit( -1 );
37     }else {
38         while( ( pCurDir = readdir( pDir ) ) != NULL ) {
39             printf( "%s\n", pCurDir->d_name );
40         }
41     }
42 }
View Code

这个简易的ls功能,列举出了所有的文件( 包括隐藏的 ), 但是很多的信息不全,如: 权限,用户和组,修改时间,文件大小,链接数目等,stat这个api可以获取文件的这些信息

stat:获取文件状态信息

原型:int stat(const char *pathname, struct stat *buf), 第一个参数:文件名, 第二个参数:保存文件状态信息的结构体( man 2 stat 有结构体相关说明 )

1、获取文件的大小

 1 /*================================================================
 2 *   Copyright (C) 2018 . All rights reserved.
 3 *   
 4 *   文件名称:stat.c
 5 *   创 建 者:ghostwu(吴华)
 6 *   创建日期:2018年01月09日
 7 *   描    述:
 8 *
 9 ================================================================*/
10 
11 #include 
12 #include 
13 
14 #define FILENAME "/etc/passwd"
15 
16 int main(int argc, char *argv[])
17 {
18     struct stat filestat;
19     
20     if( -1 == stat( FILENAME, &filestat ) ) {
21         perror( "file stat" );
22         return -1;
23     }else {
24         printf( "the size of %s is %ld\n",FILENAME,  filestat.st_size );
25     }
26 
27     return 0;
28 }
View Code

2、读取文件st_mode(权限位), 用户id, 组id, 修改时间,链接数目

 1 /*================================================================
 2 *   Copyright (C) 2018 . All rights reserved.
 3 *   
 4 *   文件名称:stat2.c
 5 *   创 建 者:ghostwu(吴华)
 6 *   创建日期:2018年01月09日
 7 *   描    述:
 8 *
 9 ================================================================*/
10 
11 #include 
12 #include 
13 #include <string.h>
14 #include 
15 
16 void show_info( char *file, struct stat* statinfo );
17 void show_time( time_t filetime );
18 char* format_time( char* dsttime, const char* srctime );
19 
20 int main(int argc, char *argv[])
21 {
22     struct stat fileinfo;
23     if( argc > 1 ) {
24         /*调试信息
25         printf( "%s\n", argv[1] );
26         int res = stat( argv[1], &fileinfo );
27         printf( "%d\n", res );
28         */
29         if( stat( argv[1], &fileinfo ) != -1 ) {
30             show_info( argv[1], &fileinfo );
31         }
32     }else {
33         perror( "get args from terminal" );
34     }
35     
36     return 0;
37 }
38 
39 void show_info( char* file, struct stat* statinfo ){
40     printf( "%s文件信息如下:\n", file );
41     printf( "st_mode = %d\n", statinfo->st_mode );
42     printf( "links = %ld\n", statinfo->st_nlink );
43     printf( "uid = %d\n", statinfo->st_uid );
44     printf( "gid = %d\n", statinfo->st_gid );
45     printf( "file size = %ld\n", statinfo->st_size );
46     show_time( statinfo->st_mtime );
47 }
48 
49 void show_time( time_t filetime ) {
50     struct tm* ptm;
51     ptm = localtime( &filetime );
52 
53     int month = ptm->tm_mon + 1;
54     int day = ptm->tm_mday;
55     int hour = ptm->tm_hour;
56     int min = ptm->tm_min;
57 
58     char srchour[3] = "0";
59     char srcmin[3] = "0";
60     char dsthour[3] = "0";
61     char dstmin[3] = "0";
62     sprintf( srchour, "%d", hour );
63     sprintf( srcmin, "%d", min );
64     format_time( dsthour, srchour );
65     format_time( dstmin, srcmin );
66 
67     printf( "文件最后修改时间: %d月\t%d\t%s:%s\n", month, day, dsthour, dstmin );
68 }
69 
70 char* format_time( char* dsttime, const char* srctime ) {
71     if( strlen( srctime ) < 2 ) {
72         return strcat( dsttime, srctime );
73     }
74     return strcpy( dsttime, srctime );
75 }
View Code

3、权限st_mode转字符权限位( 如: -rwxrwxrwx ), 用户id和组id转用户名和组名称,判断文件类型

  1 /*================================================================
  2 *   Copyright (C) 2018 . All rights reserved.
  3 *   
  4 *   文件名称:stat3.c
  5 *   创 建 者:ghostwu(吴华)
  6 *   创建日期:2018年01月09日
  7 *   描    述:文件类型与权限位
  8 *
  9 ================================================================*/
 10 
 11 #include 
 12 #include 
 13 #include 
 14 #include <string.h>
 15 #include 
 16 #include 
 17 #include 
 18 
 19 void do_ls( char* filename );
 20 void show_filetype( char* filename, int filemode );
 21 void show_filetype2( char* filename, int filemode );
 22 void mode_to_letters( int filemode, char str[] );
 23 //用户id转名称
 24 char* uid_to_name( uid_t uid );
 25 //组id转名称
 26 char* gid_to_name( gid_t gid );
 27 
 28 int main(int argc, char *argv[])
 29 {
 30     if( argc < 2 ) {
 31         printf( "usage:%s file\n", argv[0] );
 32         return -1;
 33     }else {
 34         do_ls( argv[1] );
 35     }
 36     return 0;
 37 }
 38 
 39 char* uid_to_name( uid_t uid ){
 40     return getpwuid( uid )->pw_name;
 41 }
 42 
 43 char* gid_to_name( gid_t gid ){
 44     return getgrgid( gid )->gr_name;
 45 }
 46 
 47 void do_ls( char* filename ) {
 48     struct stat fileinfo;
 49     if( stat( filename, &fileinfo ) == -1 ) {
 50         printf( "%s open failure\n", filename );
 51         exit( -1 );
 52     }
 53     //printf( "st_mode = %d\n", fileinfo.st_mode );    
 54     show_filetype( filename, fileinfo.st_mode );
 55     show_filetype2( filename, fileinfo.st_mode );
 56     char file_permission[10];
 57     mode_to_letters( fileinfo.st_mode, file_permission );
 58     printf( "%s\n", file_permission  );
 59     printf( "用户:%s\n", uid_to_name( fileinfo.st_uid ) );
 60     printf( "组:%s\n", gid_to_name( fileinfo.st_gid ) );
 61 }
 62 
 63 //掩码判断文件类型
 64 void show_filetype( char* filename, int filemode ){
 65     //用st_mode的值跟0170000这个掩码相位与的结果 判断文件类型
 66     if ( ( filemode & 0170000 ) == 0100000 ){
 67         printf( "%s是普通文件\n", filename );
 68     }else if( ( filemode & 0170000 ) == 0040000 ){ 
 69         printf( "%s是目录\n", filename );
 70     }else if ( ( filemode & S_IFMT ) == S_IFLNK ){
 71         printf( "%s是符号链接\n", filename );
 72     }
 73 }
 74 
 75 //用宏判断文件类型
 76 void show_filetype2( char* filename, int filemode ){
 77     if( S_ISREG( filemode ) ) {
 78         printf( "%s是普通文件\n", filename );
 79     }else if( S_ISDIR( filemode ) ) {
 80         printf( "%s是目录\n", filename );
 81     }else if( S_ISLNK( filemode ) ){
 82         printf( "%s是符号链接\n", filename );
 83     }
 84 }
 85 
 86 //数字解码成字母权限位
 87 void mode_to_letters( int filemode, char str[] ) {
 88     strcpy( str, "----------" );
 89     if( S_ISREG( filemode ) ) str[0] = '-';
 90     if( S_ISDIR( filemode ) ) str[0] = 'd';
 91     if( S_ISLNK( filemode ) ) str[0] = 'l';
 92 
 93     //用户权限位
 94     if( filemode & S_IRUSR ) str[1] = 'r';
 95     if( filemode & S_IWUSR ) str[2] = 'w';
 96     if( filemode & S_IXUSR ) str[3] = 'x';
 97 
 98     //组权限位
 99     if( filemode & S_IRGRP ) str[4] = 'r';
100     if( filemode & S_IWGRP ) str[5] = 'w';
101     if( filemode & S_IXGRP ) str[6] = 'x';
102 
103     //其他组权限位
104     if( filemode & S_IROTH ) str[7] = 'r';
105     if( filemode & S_IWOTH ) str[8] = 'w';
106     if( filemode & S_IXOTH ) str[9] = 'x';
107 }
View Code

综合上面3个小实例,可以得到格式化比较好的ls命令版本:

  1 /*================================================================
  2 *   Copyright (C) 2018 . All rights reserved.
  3 *   
  4 *   文件名称:myls2.c
  5 *   创 建 者:ghostwu(吴华)
  6 *   创建日期:2018年01月09日
  7 *   描    述:ls命令( version 1.2 )
  8 *
  9 ================================================================*/
 10 
 11 #include 
 12 #include 
 13 #include 
 14 #include 
 15 #include 
 16 #include 
 17 #include 
 18 #include <string.h>
 19 #include 
 20 #include 
 21 #include 
 22 #include 
 23 
 24 void do_ls( char [] );
 25 void do_stat( char* filename );
 26 void show_list( char* filename, struct stat* statinfo );
 27 void mode_to_letters( mode_t filemode, char str[] );
 28 void show_time( time_t filetime );
 29 char* format_time( char* dsttime, const char* srctime );
 30 
 31 //用户id转名称
 32 char* uid_to_name( uid_t uid );
 33 //组id转名称
 34 char* gid_to_name( gid_t gid );
 35 
 36 int main(int argc, char *argv[])
 37 {
 38     if( argc == 1 ) {
 39         do_ls( "." );
 40     }else {
 41         while( --argc ) {
 42             printf( "arg=%s\n", * ++argv );
 43             do_ls( *argv );
 44         }
 45     }
 46     return 0;
 47 }
 48 
 49 void do_ls( char dir_entry[] ) {
 50     DIR* pDir;
 51     struct dirent* pCurDir;
 52     if( ( pDir = opendir( dir_entry ) ) == NULL ){
 53         perror( "read dir" );
 54         exit( -1 );
 55     }else {
 56         while( ( pCurDir = readdir( pDir ) ) != NULL ) {
 57             do_stat( pCurDir->d_name );
 58         }
 59         closedir( pDir );
 60     }
 61 }
 62 
 63 //得到文件信息
 64 void do_stat( char* filename ){
 65     struct stat statinfo;
 66     if ( stat( filename, &statinfo ) == -1 ) {
 67         printf( "打开%s失败\n", filename );
 68         exit( -1 );
 69     }else {
 70         show_list( filename, &statinfo );
 71     }
 72 }
 73 
 74 //显示文件列表
 75 void show_list( char* filename, struct stat* statinfo ) {
 76     mode_t st_mode = statinfo->st_mode;
 77 
 78     char str[10];
 79     mode_to_letters( st_mode, str );
 80     printf( "%s\t", str );
 81 
 82     printf( "%ld\t", statinfo->st_nlink ); //符号链接
 83     printf( "%s\t\t", uid_to_name( statinfo->st_uid ) ); //用户名
 84     printf( "%s\t", gid_to_name( statinfo->st_gid ) ); //组名
 85     printf( "%10ld", statinfo->st_size ); //文件大小
 86     show_time( statinfo->st_mtime ); //最后一次修改时间
 87     printf( "\t%s", filename );
 88 
 89     printf( "\n" );
 90 }
 91 
 92 char* uid_to_name( uid_t uid ){
 93     return getpwuid( uid )->pw_name;
 94 }
 95 
 96 char* gid_to_name( gid_t gid ){
 97     return getgrgid( gid )->gr_name;
 98 }
 99 
100 void mode_to_letters( mode_t filemode, char str[] ) {
101 
102     strcpy( str, "----------" );
103     if( S_ISREG( filemode ) ) str[0] = '-';
104     if( S_ISDIR( filemode ) ) str[0] = 'd';
105     if( S_ISLNK( filemode ) ) str[0] = 'l';
106 
107     //用户权限位
108     if( filemode & S_IRUSR ) str[1] = 'r';
109     if( filemode & S_IWUSR ) str[2] = 'w';
110     if( filemode & S_IXUSR ) str[3] = 'x';
111 
112     //组权限位
113     if( filemode & S_IRGRP ) str[4] = 'r';
114     if( filemode & S_IWGRP ) str[5] = 'w';
115     if( filemode & S_IXGRP ) str[6] = 'x';
116 
117     //其他组权限位
118     if( filemode & S_IROTH ) str[7] = 'r';
119     if( filemode & S_IWOTH ) str[8] = 'w';
120     if( filemode & S_IXOTH ) str[9] = 'x';
121 }
122 
123 void show_time( time_t filetime ) {
124     struct tm* ptm;
125     ptm = localtime( &filetime );
126 
127     int month = ptm->tm_mon + 1;
128     int day = ptm->tm_mday;
129     int hour = ptm->tm_hour;
130     int min = ptm->tm_min;
131 
132     char srchour[3] = "0";
133     char srcmin[3] = "0";
134     char dsthour[3] = "0";
135     char dstmin[3] = "0";
136     sprintf( srchour, "%d", hour );
137     sprintf( srcmin, "%d", min );
138     format_time( dsthour, srchour );
139     format_time( dstmin, srcmin );
140 
141     printf( "%4d月%4d%4s:%2s", month, day, dsthour, dstmin );
142 }
143 
144 char* format_time( char* dsttime, const char* srctime ) {
145     if( strlen( srctime ) < 2 ) {
146         return strcat( dsttime, srctime );
147     }
148     return strcpy( dsttime, srctime );
149 }
View Code

 

总结:

1)opendir和readdir的用法

2)结构体struct dirent的应用

3)stat的用法

你可能感兴趣的:(linux系统编程:自己动手写一个ls命令)