Chinaunix首页 | 论坛 | 博客
  • 博客访问: 858818
  • 博文数量: 286
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1841
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-09 16:26
文章分类

全部博文(286)

文章存档

2016年(38)

2015年(248)

我的朋友

分类: LINUX

2015-10-08 20:10:02


  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <sys/stat.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>
  8. #include <linux/limits.h>
  9. #include <dirent.h>
  10. #include <grp.h>
  11. #include <pwd.h>
  12. #include <errno.h>

  13. #define        PARAM_NONE    0    // 无参数
  14. #define        PARAM_A        1    // -a: 显示所有文件
  15. #define        PARAM_L        2    // -l:一行显示一个文件的详细信息

  16. #define        MAXROWLEN    80    // 一行显示的最多字符数

  17. int        g_leave_len = MAXROWLEN;    // 一行剩余长度,用于输出对齐
  18. int        g_maxlen;            // 存放某目录下最长文件名的长度

  19. /* 错误处理函数,打印出错误所在行的行数和错误信息 */
  20. void my_err(const char *err_string, int line)
  21. {
  22.     fprintf(stderr, "line:%d ", line);
  23.     perror(err_string);
  24.     exit(1);
  25. }

  26. /* 获取文件属性并打印 */
  27. void display_attribute(struct stat buf, char * name)
  28. {
  29.     char        buf_time[32];
  30.     struct passwd    *psd;    //从该结构体中获取文件所有者的用户名
  31.     struct group    *grp;    //从该结构体中获取文件所有者所属组的组名

  32.     /*获取并打印文件类型*/
  33.     if (S_ISLNK(buf.st_mode)) {
  34.         printf("l");
  35.     } else if (S_ISREG(buf.st_mode)) {
  36.         printf("-");
  37.     } else if (S_ISDIR(buf.st_mode)) {
  38.         printf("d");
  39.     } else if (S_ISCHR(buf.st_mode)) {
  40.         printf("c");
  41.     } else if (S_ISBLK(buf.st_mode)) {
  42.         printf("b");
  43.     } else if (S_ISFIFO(buf.st_mode)) {
  44.         printf("f");
  45.     } else if (S_ISSOCK(buf.st_mode)) {
  46.         printf("s");
  47.     }

  48.     /*获取并打印文件所有者的权限*/
  49.     if (buf.st_mode & S_IRUSR){
  50.         printf("r");
  51.     } else {
  52.         printf("-");
  53.     }
  54.     if (buf.st_mode & S_IWUSR){
  55.         printf("w");
  56.     } else {
  57.         printf("-");
  58.     }
  59.     if (buf.st_mode & S_IXUSR){
  60.         printf("x");
  61.     } else {
  62.         printf("-");
  63.     }

  64.     /*获取并打印与文件所有者同组的用户对该文件的操作权限*/
  65.     if (buf.st_mode & S_IRGRP){
  66.         printf("r");
  67.     } else {
  68.         printf("-");
  69.     }
  70.     if (buf.st_mode & S_IWGRP){
  71.         printf("w");
  72.     } else {
  73.         printf("-");
  74.     }
  75.     if (buf.st_mode & S_IXGRP){
  76.         printf("x");
  77.     } else {
  78.         printf("-");
  79.     }

  80.     /*获取并打印其它用户的对该文件的操作权限*/
  81.     if (buf.st_mode & S_IROTH){
  82.         printf("r");
  83.     } else {
  84.         printf("-");
  85.     }
  86.     if (buf.st_mode & S_IWOTH){
  87.         printf("w");
  88.     } else {
  89.         printf("-");
  90.     }
  91.     if (buf.st_mode & S_IXOTH){
  92.         printf("x");
  93.     } else {
  94.         printf("-");
  95.     }

  96.     printf(" ");

  97.     /*根据uid与gid获取文件所有者的用户名与组名*/
  98.     psd = getpwuid(buf.st_uid);
  99.     grp = getgrgid(buf.st_gid);
  100.     printf("%4d ",buf.st_nlink); // 打印文件的链接数
  101.     printf("%-8s", psd->pw_name);
  102.     printf("%-8s", grp->gr_name);

  103.     printf("%6d",buf.st_size); // 打印文件的大小
  104.     strcpy(buf_time, ctime(&buf.st_mtime));
  105.     buf_time[strlen(buf_time) - 1] = '\0';    // 去掉换行符
  106.     printf(" %s", buf_time);                // 打印文件的时间信息
  107. }

  108. /* 在没有使用-l选项时,打印一个文件名,打印时上下行之间进行对齐 */
  109. void display_single(char *name)
  110. {
  111.     int i, len;

  112.     // 如果本行不足以打印一个文件名则换行
  113.     if (g_leave_len < g_maxlen) {    
  114.         printf("\n");
  115.         g_leave_len = MAXROWLEN;
  116.     }

  117.     len = strlen(name);
  118.     len = g_maxlen - len;
  119.     printf("%-s", name);
  120.     
  121.     for (i=0; i<len; i++) {
  122.         printf(" ");
  123.     }
  124.     printf(" ");
  125.     //下面的2指示空两格
  126.     g_leave_len -= (g_maxlen + 2);
  127. }

  128. /*
  129. *    根据命令行参数和完整路径名显示目标文件
  130. *    参数flag: 命令行参数
  131. *    参数pathname: 包含了文件名的路径名
  132. */
  133. void display(int flag, char * pathname)
  134. {
  135.     int        i, j;
  136.     struct stat    buf;
  137.     char        name[NAME_MAX + 1];

  138.     /*从路径中解析出文件名*/
  139.     for (i=0, j=0; i<strlen(pathname); i++) {
  140.         if (pathname[i] == '/') {
  141.             j = 0;
  142.             continue;
  143.         }
  144.         name[j++] = pathname[i];
  145.     }
  146.     name[j] = '\0';
  147.     
  148.     /*用lstat而不是stat以方便解析链接文件*/
  149.     if ( lstat(pathname, &buf) == -1 ) {
  150.         my_err("stat", __LINE__);
  151.     }
  152.     
  153.     switch (flag) {
  154.         case PARAM_NONE: // 没有-l和-a选项
  155.             if (name[0] != '.') {
  156.                 display_single(name);
  157.             }
  158.             break;

  159.         case PARAM_A:     // -a:显示包括隐藏文件在内的所有文件
  160.             display_single(name);
  161.             break;

  162.         case PARAM_L:     // -l:每个文件单独占一行,显示文件的详细属性信息
  163.             if (name[0] != '.') {
  164.                 display_attribute(buf, name);
  165.                 printf(" %-s\n", name);
  166.             }
  167.             break;

  168.         case PARAM_A + PARAM_L:        // 同时有-a和-l选项的情况
  169.             display_attribute(buf, name);
  170.             printf(" %-s\n", name);
  171.             break;

  172.         default:
  173.             break;
  174.     }
  175. }

  176. void display_dir(int flag_param, char *path)
  177. {
  178.         DIR *dir;
  179.         struct dirent *ptr;
  180.         int count = 0;
  181.         char filenames[256][PATH_MAX+1],temp[PATH_MAX+1];

  182.         // 获取该目录下文件总数和最长的文件名
  183.         dir = opendir(path);
  184.         if (dir == NULL) {
  185.                 my_err("opendir", __LINE__);
  186.         }
  187.         while ((ptr = readdir(dir))!=NULL) {
  188.                 if (g_maxlen < strlen(ptr->d_name))
  189.                          g_maxlen = strlen(ptr->d_name);
  190.                 count++;
  191.         }
  192.         closedir(dir);

  193.         if(count>256)
  194.                 my_err("too many files under this dir",__LINE__);
  195.         

  196.         int i, j, len = strlen(path);
  197.         // 获取该目录下所有的文件名
  198.         dir = opendir(path);
  199.         for(i = 0; i < count; i++){
  200.                 ptr = readdir(dir);
  201.                 if( ptr == NULL){
  202.                         my_err("readdir",__LINE__);
  203.                 }
  204.                 strncpy(filenames[i],path,len);
  205.                 filenames[i][len] = '\0';
  206.                 strcat(filenames[i],ptr->d_name);
  207.                 filenames[i][len+strlen(ptr->d_name)] = '\0';
  208.         }

  209.         // 使用冒泡法对文件名进行排序,排序后文件名按字母顺序存储于filenames
  210.         for(i = 0; i < count-1; i++)
  211.                 for(j = 0; j < count-1-i; j++) {
  212.                         if( strcmp(filenames[j],filenames[j+1]) > 0 ) {
  213.                                 strcpy(temp,filenames[j+1]);
  214.                                 temp[strlen(filenames[j+1])] = '\0';
  215.                                 strcpy(filenames[j+1],filenames[j]);
  216.                                 filenames[j+1][strlen(filenames[j])] = '\0';
  217.                                 strcpy(filenames[j], temp);
  218.                                 filenames[j][strlen(temp)] = '\0';
  219.                         }
  220.                 }
  221.         for(i = 0; i < count; i++)
  222.                 display(flag_param, filenames[i]);

  223.         closedir(dir);

  224.         // 如果命令行中没有-l选项,打印一个换行符
  225.         if( (flag_param & PARAM_L) == 0)
  226.                 printf("\n");}


  227. int main(int argc, char ** argv)
  228. {
  229.     int        i, j, k, num;
  230.     char        path[PATH_MAX+1];
  231.     char        param[32];     // 保存命令行参数,目标文件名和目录名不在此列
  232.     int        flag_param = PARAM_NONE; // 用来标志参数种类,即是否有-l和-a选项
  233.     struct stat    buf;


  234.     /*命令行参数的解析,分析-l、-a、-al、-la选项*/
  235.     j = 0,
  236.     num = 0;
  237.     for (i=1; i<argc; i++) {
  238.         if (argv[i][0] == '-') {
  239.             for(k=1; k < strlen(argv[i]); k++,j++) {
  240.                 param[j] = argv[i][k];    // 获取-后面的参数保存到数组param中
  241.             }
  242.         num++; // 保存"-"的个数
  243.         }
  244.     }
  245.     
  246.     /*只支持参数a和l,如果含有其他选项就报错*/
  247.     for(i=0; i<j; i++) {
  248.         if (param[i] == 'a') {
  249.             flag_param |= PARAM_A;
  250.             continue;
  251.         } else if (param[i] == 'l') {
  252.             flag_param |= PARAM_L;
  253.             continue;
  254.         } else {
  255.             printf("my_ls: invalid option -%c\n", param[i]);
  256.             exit(1);
  257.         }
  258.     }
  259.     param[j] = '\0';
  260.     
  261.     // 如果没有输入文件名或目录,就显示当前目录
  262.     if ((num + 1) == argc) {    
  263.         strcpy(path, "./");
  264.         path[2] = '\0';
  265.         display_dir(flag_param, path);
  266.         return 0;
  267.     }

  268.     i=1;
  269.     do {
  270.         // 如果不是目标文件名或目录,解析下一个命令行参数
  271.         if (argv[i][0] == '-') {
  272.             i++;
  273.             continue;    
  274.         } else {
  275.             strcpy(path, argv[i]);

  276.             // 如果目标文件或目录不存在,报错并退出程序
  277.             if ( stat(path, &buf) == -1 )
  278.                 my_err("stat", __LINE__);    

  279.             if ( S_ISDIR(buf.st_mode) ) { // argv[i]是一个目录
  280.                 // 如果目录的最后一个字符不是'/',就加上'/'
  281.                 if ( path[ strlen(argv[i])-1 ] != '/') {
  282.                     path[ strlen(argv[i]) ] = '/';
  283.                     path[ strlen(argv[i])+1 ] = '\0';
  284.                 }
  285.                 else
  286.                     path[ strlen(argv[i]) ] = '\0';

  287.                 display_dir(flag_param,path);
  288.                 i++;
  289.             }
  290.             else { //argv[i]是一个文件
  291.                 display(flag_param, path);
  292.                 i++;
  293.             }
  294.         }
  295.     } while (i<argc);

  296.     return 0;
  297. }

阅读(1122) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~