linux系统编程:自己动手写一个ls命令
程序员文章站
2022-06-23 19:18:39
ls用于列举目录内容,要实现这个功能,毫无疑问,需要读取目录,涉及到两个api: opendir:DIR *opendir(const char *name), 传文件名,返回一个指针,指向目录序列 readdir:struct dirent *readdir(DIR *dirp), 把opendi ......
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 <stdio.h> 12 #include <sys/types.h> 13 #include <dirent.h> 14 #include <stdlib.h> 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 <stdio.h> 12 #include <sys/stat.h> 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 <stdio.h> 12 #include <sys/stat.h> 13 #include <string.h> 14 #include <time.h> 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 <stdio.h> 12 #include <stdlib.h> 13 #include <sys/stat.h> 14 #include <string.h> 15 #include <sys/types.h> 16 #include <pwd.h> 17 #include <grp.h> 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 <stdio.h> 12 #include <sys/types.h> 13 #include <dirent.h> 14 #include <stdlib.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <unistd.h> 18 #include <string.h> 19 #include <sys/types.h> 20 #include <pwd.h> 21 #include <grp.h> 22 #include <time.h> 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的用法