吴昊品命令行解释程序核心算法 Round 13 —— UNIX的ls命令

 

 

 UNIX

  如图的那只大企鹅就是UNIX/LINUX的logo,关于开源的UNIX操作系统,就不多说了。说说有趣的事情吧,也就是UNIX与企鹅的来历。UNIX操作系统,是美国AT&T公司于1971年在PDP-11上运行的操作系统。具有多用户、多任务的特点,支持多种处理器架构,最早由肯·汤普逊(Kenneth Lane Thompson)、丹尼斯·里奇(Dennis MacAlistair Ritchie)和Douglas McIlroy于1969年在AT&T的贝尔实验室开发。目前它的商标权由国际开放标准组织(The Open Group)所拥有。

  Unix/Linux与企鹅

 企鹅是南极洲的标志性动物,根据国际公约,南极洲为全人类共同所有,不属于当今世界上的任何国家,当今任何国家无权将南极洲纳入其版图。

    Linux选择企鹅图案作标志,其含意也是表明:开源的Linux,为全人类共同所有,任何公司无权将其私有。

    企鹅背后的故事还有很多

    我 想很多人都不是很清楚企鹅Tux究竟是怎样成为Linux的标志的.为什么选企鹅?而不是选择狮子老虎?有人说因为Linus是 芬兰人,所以选择企鹅. 有人说因为其他动物图案都被用光了,Linus只好选择企鹅. 带着这个疑问, 我将Jennifer的采访收获带回给大家, 祝大家新年快乐,像Tux那样笑口常开。

     长期以来,国外有人报怨Tux长得太象搞笑动画片里的辛普森形象, 或者有人认为这个形象不够严肃(以前有过网友调查, 有人认为Linux形象应该是雷神之锤那种火焰, 或者IBM那种大气)

    Linus却认为, Linux的logo应该是一种有生趣并可爱的图案, 而有生趣并带着友好表情的图案意味着你应该选择某种动物logo.但是很多Linux业界中人可不是在寻求可爱和友好, 有些人认为Linux的logo根本不该走“可爱”这个方向, 应该是沉重严肃的。

    在 1996年, 5岁的Linux操作系统开始在世界范围内被广泛应用, Linus开始考虑给这个操作系统创作一个logo. 但是他的思考范围仍然在动物世界里: 信天翁,鸭嘴兽, 老鹰,还曾经想到过狐狸.就这样,一只只动物在Linus脑中闪过. 最终,他的灵感闪光,他想起曾经在澳大利亚被一种鸟咬过,咬他的不是别的鸟,就是企鹅.

    选 定了企鹅作为logo之后,linus在1996年的Linux内核邮件列表中讨论寻找一只丰满敦实的企鹅时形容到:"不要太胖, 而且应该是坐着的姿态 ?想象一下装满豆子的袋子."(Larry Ewing给他的主意, 当时22岁的电子工程本科生Larry Ewing在学校科学计算研究所工作时看到了邮件列表里关于logo的讨论.这位热心的艺术家发现执笔画企鹅比做毕业论文有趣.)

    Ewing 使用GIMP创建了企鹅的基本形态, 准备公布的时候,他突然想到,这只企鹅如果出在别人手里会是什么样?于是在保留Ewing和GIMP名字的前提下,他允许用户自由添加修改这只企鹅的造 型, 也衍生了现在诸多企鹅造型. 目前Ewing是Ximian的开发人员,Ximian的猴子图案也出自他笔下。

    至于企鹅的名字: Tux. 因为企鹅总是黑白一身,当时外界认为这个名字来自燕尾服(Txuedo)一词.事实上Tux是“Torvalds' UniX”的缩写。

    现 在, 企鹅Tux已经是Linux的标志,或者可以说品牌. 笑容可掬的Tux吸引了世界众多爱好自由的电脑爱好者. Tux自身的含义也随着Linux的壮大不断发展, 按ewing的话来讲:"这真是一件有意思的事情,我只花了20多个小时画了只企鹅, 同时我也花了四五年时间写程序代码.但是我所了解的企鹅远远比任何代码的含义还要深刻。"

  UNIX的ls命令

  ls是一个由POSIX单一Unix标准规范的命令,在Unix类Unix系统中都有实现。ls是英文list segment的缩写,用于列出文件,是Unix系统中使用非常频繁的命令。ls首次出现于原始版本的AT&T Unix中。它的名字来源于Multics操作系统的一个类似命令,意思是“列出文件块”(list segment)。目前有两种主流版本的ls:一种是自由软件基金会开发的GNU核心程序的组成部分;另一种由各种BSD版本发布,如FreeBSDOpenBSDNetBSD苹果公司Darwin。两种版本都是自由以及开源软件

  ls的使用

  Unix类Unix操作系统中都有当前目录的概念,也即程序目前在目录树中的位置。

当不加参数运行时,ls列出当前目录下的所有文件和目录名。如果以目录名作为参数,则会列出该目录下的文件。用户也可以指定多个文件和目录作为参数,ls则会列出所有指定的文件和目录中的文件名。

 以 "."(圆点)开头的目录在一般情况下不会被列出。用户可以加 -a 选项查看所有文件。

 不加参数时,ls仅仅列出文件和目录的名称,不加任何修饰。这通常让人很难区分文件的类型、大小、权限等属性。显示文件常用信息的一些参数如下:

  • -llong)长格式,显示文件类型、权限、的数目、文件拥有者、文件所在的、大小、日期和文件名。硬链接
  • -F 在不同类型的文件的文件名结尾追加一个字符以示区别。可执行文件后加"*",目录后加"/",管道文件后加"|",套接字文件后加"=",普通文件没有后缀。
  • -aall)显示所有文件,包括以 . 开头的文件名(默认不显示)。
  • -Rrecursive)迭代显示目录下所有的子目录。ls -R/会显示文件系统中的所有文件。
  • -ddirectory)显示目录本身的信息,而不是列出目录下的文件。

 在某些环境下,使用参数"--color"(GNU版)或者"-G"(FreeBSD版)后,ls会根据文件类型输出不同色彩的格式。GNU版的ls根据文件的类型、扩展名和使用权限来决定颜色,而FreeBSD版的ls仅仅检查文件类型和使用权限。

 使用上述彩色选项时,输出示例如下:

 

  Warming up:

  (Source: POJ 1589)为一个文件块列出一个表格,Input是一些文件名,我们需要在Output中按照类ls所规定的一定格式列表输出(也就是ls的目录列表功能)。

  Solve:

  

 1 #include<stdio.h>
 2  
 3   // 假设100个文件名,每个文件名62个字符左右
 4    char name[ 100][ 62];
 5 
 6   int cmp( const  void *a, const  void *b)
 7  {
 8     return strcmp(( char *)a,( char *)b);
 9  }
10 
11   int main()
12  {
13     int n;
14     int i,j;
15     int tmp;
16     int max_len,row,col;
17     // freopen("input","r",stdin);
18      while(scanf( " %d ",&n)!=EOF)
19    {
20       for(i=n;i< 100;i++)
21        name[i][ 0]= ' \0 ';
22      max_len=- 1;
23      row= 1;
24       for(i= 0;i<n;i++)
25        scanf( " %s ",name[i]);
26       for(i= 0;i<n;i++)
27      {
28        tmp=strlen(name[i]);
29         if(max_len<tmp) max_len=tmp;
30      }
31       // 这是规定的格式
32       col= 62/(max_len+ 2);
33       while(row*col<n) row++;
34      qsort(name,n, sizeof(name[ 0]),cmp);
35      printf( " ------------------------------------------------------------\n ");
36       for(i= 0;i<row;i++)
37      {
38         for(j= 0;j<col;j++)
39           // 输出第j*row+i个文件的文件名
40           printf( " %-*s ",max_len+ 2,name[j*row+i]);
41        printf( " \n ");
42      }
43    }
44     return  0;
45  }

  Format:

(Source参考了UNIX v6的部分源码)

 源码貌似用到了很多Linux下C,而且过于庞大复杂而又没多少注释,所以我暂时看不懂,我会翻阅一些资料将其弄懂,现在,就只能放在这里了。

 

  // 这里是Linux下的C,和一般的C有一些区别,一般的C的库函数一共有15个,我会在《吴昊品工业级别项目源代码》中阐明的
 #include    <pwd.h>
 #include    <grp.h>
 #include     <fts.h>
 #include     <err.h>
 #include    <time.h>
 #include    <errno.h>
 #include    <ctype.h>
 #include    <stdio.h>
 #include     <string.h>
 #include     <stdlib.h>
 #include    <unistd.h>
 #include     <sys/stat.h>
 #include    <sys/ioctl.h>

 #define IS_NOPRINT(b)     ((b)->fts_number == 1)    /* 1 表示为not print */
 
 struct buf
 {
   int num;
   int total;
   int bcfile;
   int maxlen;
   int usrlen;
   //管道长度
   int grplen;
   int linklen;
   int sizelen;
   int inodelen;
   int blocklen;
   FTSENT *list;        /* FTS, FTSENT结构和fts函数具体参考/usr/include/fts.h,联机帮助会有更多的资料以供参考(man fts_open可以获得联机帮助的信息 */
 }b;

 typedef struct name
 {
   //union,联合体,可以两个变量共用一个内存,使得空间被占用地更小
   union
   {
     int uid;
     char *usr;
   }usr;        
   union
   {
     int gid;
     char *grp;
   }grp;
   char date[0];      /* 为了节省空间而做出的策略,date不占用任何空间 */
 }NAME;
 
 //声明各种变量和各种函数
 int col;            
 int rflg = 1;
 int putout = 0;
 int seeusr = 1, seegrp = 1;
 int seeuid, seegid, singleflg, fts_options;
 int Aflg, Cflg, Fflg, Lflg, Rflg, Sflg, Uflg;
 int cflg, dflg, fflg, iflg, lflg, oflg, pflg, qflg, sflg, tflg, uflg;
 static char *com_name;    

 void printone(void);
 void printcol(void);
 void printlong(void);
 void q_copy(char *a, char *b);
 void do_ls(int argc, char *argv[]);
 void do_print(FTSENT *fp, FTSENT *list);
 int cmparg(const FTSENT **a, const FTSENT **b);
 int cmpname(const FTSENT *a, const FTSENT *b);
 int cmptime(const FTSENT *a, const FTSENT *b);
 int cmpsize(const FTSENT *a, const FTSENT *b);
 static void (*printfcn)(void);    
 static void printtime(time_t t);
 static void printlink(FTSENT *p);
 static void modetostr(mode_t mode, char *buf);
 static int printtype(mode_t mode);
 static int printname(FTSENT *b, int flg);
 static int (*sortfcn)(const FTSENT *a, const FTSENT *b);

 int main(int argc, char *argv[])
 {
   char *p;
   //寄存器变量
   register int c;
   struct winsize wbuf;
   static char dot[] = ".", *dotav[] = { dot, (char *)NULL };
   
   com_name = *argv;
   if(isatty(STDOUT_FILENO))
   {        
     /* 得出终端的宽度,默认宽度为80,如果获取失败,将激活-1选项 */
     if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &wbuf) == -1 || wbuf.ws_col == 0)
     {
       if(p = getenv("COLUMNS"))
         col = atoi(p);
       else
         col = 80;
     }
     else
       col = wbuf.ws_col;
     Cflg = qflg = 1;
   }
   else
     singleflg = 1;
   sortfcn = cmpname;            
   printfcn = printcol;
   fts_options = FTS_PHYSICAL;
   while(--argc > 0 && (*++argv)[0] == '-')
   {
     while(c = *++argv[0])
       switch(c)
       {
         case '1':
            Cflg = 0;
            singleflg = 1;
            printfcn = printone;
            break;
         case 'A':
            Aflg = 1;
            break;
         case 'C':
            lflg = 0;
            Cflg = 1;
            printfcn = printcol;
            break;
         case 'F':
            pflg = 0;    
            Fflg = 1;
            break;
         case 'H':
            fts_options |= FTS_COMFOLLOW;
            break;
         case 'L':
            fts_options &= ~FTS_PHYSICAL;
            fts_options |= FTS_LOGICAL;
            break;
         case 'R':    
            Rflg = 1;    
            dflg = 0;
            break;
         case 'S':
            Sflg = 1;
            sortfcn = cmpsize;
            break;
         case 'U':
            Uflg = 1;
            sortfcn = (int(*)(const FTSENT **, const FTSENT **))NULL;    /* 这一步实则不必要,编写的理由是个人的感情因素 */
            break;
         case 'a':         
            Aflg = 1;
            fts_options |= FTS_SEEDOT;
            break;
         case 'c':        /* -u,-c,-t和标准ls命令的表现方式一样,详见联机帮助,可ls --help或man ls */
            uflg = 0;    
            cflg = 1;
            if(lflg == 0)
                sortfcn = cmptime;
            break;
         case 'd':
            dflg = 1;
            Rflg = 0;
            break;
         case 'f':        /* -f和标准ls一样,联机帮助有其说明,注意此选项的输出是没有颜色的 */
            fts_options |= FTS_SEEDOT;
            fflg = Aflg = Uflg = 1;
            sortfcn = (int(*)(const FTSENT **, const FTSENT **))NULL;
            lflg = sflg = tflg = 0;    
            break;    
         case 'g':
            lflg = 1;
            seeusr = 0;
            printfcn = printlong;
            break;
         case 'i':
            iflg = 1;
            break;
         case 'l':
            Cflg = 0;
            lflg = 1;
            if(tflg == 0)
                sortfcn = cmpname;
            printfcn = printlong;
            break;
         case 'n':
            lflg = 1;
            seeuid = seegid = 1;
            break;
         case 'o':
            lflg = 1;
            seegrp = 0;
            printfcn = printlong;
            break;
         case 'p':         /* -p和-F的表现和标准ls命令一样,具体参阅联机帮助 */
            Fflg = 0;
            pflg = 1;
            break;
         case 'q':
            qflg = 1;
            break;    
         case 'r':
            rflg = -1;
            break;
         case 's':
            sflg = 1;
            break;
         case 't':
            tflg = 1;
            sortfcn = cmptime;
            break;
         case 'u':
            cflg = 0;
            uflg = 1;
            if(lflg == 0)
                sortfcn = cmptime;    
            break;
         default:
            fprintf(stderr, "Usage: %s -[1ACFLHRTacdfgilnoqrstu] [file ...]\n", com_name);
            exit(1);    
        }
    }
    if(lflg)    /* -l命令会导致-1选项的失效 */
        printfcn = printlong;
    if(argc)
        do_ls(argc, argv);
    else
        do_ls(1, dotav);                
    return 0;
}

void do_ls(int argc, char *argv[])
{
    FTS *ftsp;
    register FTSENT *p, *tmp;

    ftsp = fts_open(argv, fts_options, Uflg ? NULL : cmparg);    /* 把所有文件读入一棵树中, 详见联机帮助 */
    if(ftsp == (FTS *)NULL){
        fprintf(stderr, "%s: fts_open error\n", com_name);
        exit(1);
    }
    do_print(NULL, fts_children(ftsp, 0));
    if(dflg)
        return;
    while(p = fts_read(ftsp)){
        switch(p->fts_info){
        case FTS_DC:
            warnx("%s: directory causes a cycle", p->fts_name);    /* err, warn, warnx等函数具体可查看err.h头文件和man warn来了解其功能 */
            break;
        case FTS_ERR:
        case FTS_DNR:
            errno = p->fts_errno;    /* fts函数不会设置errno,函数具体功能参阅联机帮助 */
            warn("%s", p->fts_name);
            break;
        case FTS_D:
            if(p->fts_level != 0 && p->fts_name == '.' && Aflg == 0)
                break;
            if(putout)
                printf("\n%s:\n", p->fts_path);
            else if(argc > 1){
                printf("%s:\n", p->fts_path);
                putout = 1;
            }
            tmp = fts_children(ftsp, 0);
            do_print(p, tmp);
            if(Rflg == 0 && tmp)
                fts_set(ftsp, p, FTS_SKIP);
            break;
        default:
            break;
        }
    }
    fts_close(ftsp);    /* 分配的内存会自动释放 */
}

void do_print(FTSENT *fp, FTSENT *list)
{
    NAME *np;
    char buf[20];
    struct group *gp;
    struct passwd *pw;
    register FTSENT *p;
    register struct stat *q;
    int num, total, needstat;
    int n, m, in, im, sn, sm;
    int un, um, gn, gm, ln, lm, bn, bm, bcfile;

    if(list == NULL)
        return;
    num = total = bcfile = 0;
    n = m = in = im = sn = sm = 0;
    un = um = gn = gm = ln = lm = bn = bm = 0;
    needstat = iflg | sflg | lflg;
    for(p = list; p; p = p->fts_link){
        if(p->fts_info == FTS_ERR || p->fts_info == FTS_NS){
            errno = p->fts_errno;
            warn("%s", p->fts_name);
            p->fts_number = 1;
            continue;
        }
        if(fp == NULL){    /* 若为命令行参数 */
            if(p->fts_info == FTS_D && dflg == 0){
                p->fts_number = 1;    
                continue;
            }
        }
        else{
            if(p->fts_name[0] == '.' && Aflg == 0){
                p->fts_number = 1;
                continue;
            }
        }
        if(qflg)    /* 以?代替不可打印的字符 */
            q_copy(p->fts_name, p->fts_name);
        if(m < (n = p->fts_namelen))
            m = n;
        if(needstat){
            q = p->fts_statp;
            if(iflg && im < (in = q->st_ino))
                im = in;        
            if(sflg && bm < (bn = q->st_blocks))
                bm = bn;
            if(sm < (sn = q->st_size))
                sm = sn;
            if(lm < (ln = q->st_nlink))
                lm = ln;
            total += q->st_blocks;
            if(lflg){
                if(seeuid){        /* 与标准ls不同,本程序,-n选项会使-g -o选项失效 */
                    if(um < (un = q->st_uid))
                        um = un;
                }
                else if(seeusr){
                    pw = getpwuid(q->st_uid);
                    if(pw && um < (un = strlen(pw->pw_name)))
                        um = un;
                }
                else
                    um = 0;
                if(seegid){
                    if(gm < (gn = q->st_gid))
                        gm = gn;                
                }
                else if(seegrp){
                    gp = getgrgid(q->st_gid);
                    if(gp && gm < (gn = strlen(gp->gr_name)))
                        gm = gn;
                }
                else
                    gm = 0;
                if(seeuid && seegid){
                    np = malloc(sizeof(NAME));
                    np->usr.uid = un;
                    np->grp.gid = gn;
                }
                else{
                    if((np = malloc(sizeof(NAME) + un + gn + !(!un) + !(!gn))) == NULL)    /* !(!un) + !(!gn)用来判断是否有设置seeusr和seegrp */
                        err(1, NULL);
                    if(seeusr){
                        np->usr.usr = &np->date[0];    
                        strcpy(np->usr.usr, pw->pw_name);
                    }
                    if(seegrp){
                        np->grp.grp = &np->date[un + !(!un)];
                        strcpy(np->grp.grp, gp->gr_name);
                    }
                }
                if(S_ISCHR(q->st_mode) || S_ISBLK(q->st_mode))    
                    bcfile = 1;        
                p->fts_pointer = np;    
            }
        }    
        ++num;            
    }
    if(num == 0)
        return;
    b.list = list;
    b.num = num;
    b.maxlen = m;
    if(needstat){        
        b.total = total;
        b.bcfile = bcfile;
        snprintf(buf, sizeof(buf), "%u", lm);
        b.linklen = strlen(buf);
        snprintf(buf, sizeof(buf), "%u", sm);
        b.sizelen = strlen(buf);    
        snprintf(buf, sizeof(buf), "%u", im);
        b.inodelen = strlen(buf);
        snprintf(buf, sizeof(buf), "%u", bm);
        b.blocklen = strlen(buf);
        if(seeuid && seegid){
            snprintf(buf, sizeof(buf), "%u", um);            
            b.usrlen = strlen(buf);
            snprintf(buf, sizeof(buf), "%u", gm);
            b.grplen = strlen(buf);
        }
        else{
            b.usrlen = um;
            b.grplen = gm;
        }
    }
    printfcn();
    putout = 1;    
    if(lflg)
        for(p = list; p; p = p->fts_link)
            free(p->fts_pointer);
}    

int cmparg(const FTSENT **a, const FTSENT **b)
{
    FTSENT *ap, *bp;

    ap = *(FTSENT **)a;
    if(ap->fts_info == FTS_ERR)
        return 0;    
    bp = *(FTSENT **)b;
    if(bp->fts_info == FTS_ERR)
        return 0;
    if(ap->fts_info == FTS_NS || bp->fts_info == FTS_NS)
        return cmpname(ap, bp);
    if(ap->fts_info == bp->fts_info)
        sortfcn(ap, bp);
    if(ap->fts_level == 0){        /* 命令行参数的目录默认大于文件, 详见标准ls命令的说明文档 */
        if(ap->fts_info == FTS_D){
            if(bp->fts_info != FTS_D)
                return 1;
        }
        else if(bp->fts_info == FTS_D)
            return -1;
    }
    return sortfcn(ap, bp);
}
    
int cmpname(const FTSENT *a, const FTSENT *b)
{
    return rflg * strcmp(a->fts_name, b->fts_name);
}

int cmpsize(const FTSENT *a, const FTSENT *b)
{
    return rflg * (b->fts_statp->st_size - a->fts_statp->st_size);
}

int cmptime(const FTSENT *a, const FTSENT *b)
{
    if(cflg)
        return rflg * (b->fts_statp->st_ctime - a->fts_statp->st_ctime);    
    else if(uflg)
        return rflg * (b->fts_statp->st_atime - a->fts_statp->st_atime);
    else
        return rflg * (b->fts_statp->st_mtime - a->fts_statp->st_mtime);
}

void q_copy(char *a, char *b)
{
    register char *p, *q;

    for(p = a, q = b; *p; p++, q++){
        if(isprint(*p))
            *q = *p;
        else
            *q = '?';
    }
}
    
void printone(void)
{
    register FTSENT *p;

    for(p = b.list; p; p = p->fts_link){
        if(IS_NOPRINT(p))
            continue;
        printname(p, 1);
        putchar('\n');
    }
}

void printcol(void)
{
    static int lastnum = -1;
    static FTSENT **array;    
    register FTSENT *p;
    int i, j, k, tm, cn, chn, num, len, nrow, ncol, diff, left, tmcol;

    if(b.num > lastnum){
        lastnum = b.num;
        if((array = realloc(array, sizeof(FTSENT *) * b.num)) == NULL){
            err(1, NULL);
            printone();
        }
    }
    num = 0;
    for(p = b.list; p; p = p->fts_link)
        if(p->fts_number != 1)
            array[num++] = p; i = b.maxlen;
    if(iflg)
        i += b.inodelen + 1;
    if(sflg)
        i += b.blocklen + 1;
    if(pflg || Fflg)
        i += 1;
    len = (i + 8) & ~7;    /* 规整到下一个8的倍数 */
    if(col < 2 * len){    
        printone();
        return;
    }
    ncol = col / len;
    nrow =  num / ncol;
    if(num % ncol)
        nrow++;
    tmcol = num / nrow;        
    left = num - (tmcol * nrow);    
    diff = left / nrow;
    diff += 1;            /* 每行需另外输出的的个数 */    
    if(sflg)
        printf("total = %u\n", b.total);
    tm = 0;
    for(i = 0; i < nrow; ++i){
        k = len;            /* 输出应该停止处 */
        for(j = chn = 0;  j < ncol; ++j){
            if(tm >= num)
                break;
            if(j >= tmcol){    /* 用来调整使每行的个数尽可能一样 */
                if(j < tmcol + diff && left)
                    --left;
                else
                    break;
            }
            chn += printname(array[tm++], 1);    
            while((cn = (chn + 8 & ~7)) <= k){
                putchar('\t');
                chn = cn;
            }
            k += len;
        }
        putchar('\n');
    }
}

void printlong(void)
{
    NAME *np;
    int mode;
    char buf[10];
    register FTSENT *p;
    register struct stat *sp;

    if(b.list->fts_level != 0)
        printf("total %u\n", b.total);
    for(p = b.list; p; p = p->fts_link){
        if(IS_NOPRINT(p))
            continue;
        sp = p->fts_statp;
        mode = sp->st_mode;
        if(iflg)
            printf("%*lu ", b.inodelen, sp->st_ino);
        if(sflg)
            printf("%*lu ", b.blocklen, sp->st_blocks);
        modetostr(mode, buf);    
        np = p->fts_pointer;
        printf("%s ", buf);
        printf("%*u ", b.linklen, sp->st_nlink);
        if(seeuid)
            printf("%*u ", b.usrlen, np->usr.uid);
        else if(seeusr)
            printf("%*s ", b.usrlen, np->usr.usr);
        if(seegid)
            printf("%*u ", b.grplen, np->grp.gid);
        else if(seegrp)
            printf("%*s ", b.grplen, np->grp.grp);
        if(S_ISCHR(mode) || S_ISBLK(mode))    
            printf("%3d,%3d ", major(sp->st_rdev), minor(sp->st_rdev));
        else if(b.bcfile)
            printf("%*s%*lu ", 8 - b.sizelen, "", b.sizelen, sp->st_size);
        else
            printf("%*lu ", b.sizelen, sp->st_size);
        if(cflg)
            printtime(sp->st_ctime);
        else if(uflg)
            printtime(sp->st_atime);
        else
            printtime(sp->st_mtime);
        printname(p, 0);
        if(Fflg || pflg)
            printtype(mode);        
        if(S_ISLNK(mode))
            printlink(p);
        putchar('\n');
    }
}

static void printlink(FTSENT *p)
{
    int lnklen;
    char name[256], path[256];

    if(p->fts_level == 0)
        snprintf(name, sizeof(name), "%s", p->fts_name);
    else
        snprintf(name, sizeof(name), "%s/%s", p->fts_parent->fts_accpath, p->fts_name);    
    if((lnklen = readlink(name, path, sizeof(path) - 1)) == -1){        /* readlink详见联机帮助 */
        fprintf(stderr, "\n%s: %s: %s\n", com_name, name, strerror(errno));
        return;
    }
    path[lnklen] = '\0';
    printf(" -> %s", path);
}

static void printtime(time_t t)
{
    char *s;
    time_t year, tm;

    time(&tm);
    year = tm - 60 * 30 * 24 * 60 * 60;
    s = ctime(&t);
    if(t < year)
        printf("%.7s %.4s ", s + 4, s + 20);
    else
        printf("%.12s ", s + 4);
}
    
static void modetostr(mode_t mode, char *buf)
{
    strcpy(buf, "----------");
    if(S_ISDIR(mode))
        buf[0] = 'd';
    if(S_ISCHR(mode))
        buf[0] = 'c';
    if(S_ISBLK(mode))
        buf[0] = 'b';
    if(S_ISLNK(mode))
        buf[0] = 'l';
    if(S_ISSOCK(mode))
        buf[0] = 's';
    if(S_ISFIFO(mode))
        buf[0] = 'p';
    if(mode & S_IRUSR)
        buf[1] = 'r';
    if(mode & S_IWUSR)
        buf[2] = 'w';
    if(mode & S_IXUSR)
        buf[3] = 'x';
    if(mode & S_ISUID)
        buf[3] = 's';
    if(mode & S_IRGRP)
        buf[4] = 'r';
    if(mode & S_IWGRP)
        buf[5] = 'w';
    if(mode & S_IXGRP)
        buf[6] = 'x';
    if(mode & S_ISGID)
        buf[6] = 'x';
    if(mode & S_IROTH)
        buf[7] = 'r';
    if(mode & S_IWOTH)
        buf[8] = 'w';
    if(mode & S_IXOTH)
        buf[9] = 'x';
    if(mode & S_ISVTX)
        buf[9] = 't';
}

static int printname(FTSENT *p, int flg)
{
    int np, mode;
    struct stat *sp;

    np = 0;
    sp = p->fts_statp;
    if(flg){
        if(iflg)
            np += printf("%*lu ", b.inodelen, sp->st_ino);
        if(sflg)
            np += printf("%*lu ", b.blocklen, sp->st_blocks);
    }
    mode = sp->st_mode;
    if(fflg)
        np += printf("%s", p->fts_name);
    else{                            /* 注意printf的返回值 */
        if(mode & S_ISUID){
            printf("\033[37;41m");    
            np += printf("%s", p->fts_name);
            printf("\033[0m");
        }
        else if(mode & S_ISGID){
            printf("\033[30;43m");
            np += printf("%s", p->fts_name);
            printf("\033[0m");
        }
        else if(mode & S_ISVTX){
            printf("\033[37;44m");
            np += printf("%s", p->fts_name);
            printf("\033[0m");
        }
        else{
            switch(mode & S_IFMT){
            case S_IFDIR:
                printf("\033[01;34m");
                np += printf("%s", p->fts_name);
                printf("\033[0m");
                break;
            case S_IFIFO:
                printf("\033[33m");
                np += printf("%s", p->fts_name);
                printf("\033[0m");
                break;
            case S_IFSOCK:
                printf("\033[01;35m");
                np += printf("%s", p->fts_name);
                printf("\033[0m");
                break;    
            case S_IFLNK:
                printf("\033[01;36m");
                np += printf("%s", p->fts_name);
                printf("\033[0m");
                break;
            case S_IFCHR:
            case S_IFBLK:
                printf("\033[01;33m");
                np += printf("%s", p->fts_name);
                printf("\033[0m");
                break;
            default:
                if(mode & S_IXUSR || mode & S_IXGRP || mode & S_IXOTH){
                                printf("\033[01;32m");
                    np += printf("%s", p->fts_name);
                    printf("\033[0m");
                }
                else
                    np += printf("%s", p->fts_name);
                break;
            }
        }
    }
    if(Fflg || pflg)
        np += printtype(mode);    
    return np;    
}

static int printtype(mode_t mode)
{
    switch(mode & S_IFMT){
    case S_IFDIR:
        putchar('/');
        return 1;
    case S_IFLNK:
        if(Fflg == 0)
            break;
        putchar('@');
        return 1;
    case S_IFSOCK:
        if(Fflg == 0)
            break;
        putchar('=');
        return 1;
    default:
        if(Fflg == 0)
            break;
        if(mode & (S_IXUSR | S_IXGRP | S_IXOTH)){
            putchar('*');
            return 1;
        }
        break;
    }
    return 0;
}

 

你可能感兴趣的:(round)