📄 新建 文本文档 (2).txt
字号:
/*
* 对UNUX V7 ls命令原代码的注释。
* 位置:UNIX V7/usr/src/cmd/ls.c
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <stdio.h>
#define NFILES 1024
FILE *pwdf, *dirf;
char stdbuf[BUFSIZ];
/* struc lbuf 封装了对ls有用的struct stat */
struct lbuf {
union {
char lname[15];
char *namep; //文件名
} ln;
char ltype; //文件类型
short lnum; //索引结点号
short lflags; //权限位
short lnl; //链接数
short luid; //用户ID
short lgid; //组ID
long lsize; //文件大小
long lmtime; //访问时间
};
/* 每个选项设置一个标记变量 */
int aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg;
int rflg = 1; //颠倒排序标志 如果使用-r 选项,则rflg会被置-1
long year; //这个变量被设置为从1970年1月1日午夜到当前时间六个月前所经过的秒数
int flags;
int lastuid = -1; //用户ID用于测试
char tbuf[16];
long tblocks; //文件所占用的磁盘块数
int statreq; //使用stat()系统调用的标志,如果为 1 则表示使用stat获取目录信息
struct lbuf *flist[NFILES];
struct lbuf **lastp = flist;
struct lbuf **firstp = flist;//以上三个变量表示用ls 显示信息的文件
char *dotp = "."; //设置默认读取的目录,即当前目录
char *makename(); //连接由斜杠字符分割的目录名和文件名并产生一个字符串
struct lbuf *gstat(); //读取和存储文件信息的核心函数
char *ctime(); //获得时间的函数
long nblock(); //计算文件使用的磁盘块数
#define ISARG 0100000 //用于区分一个文件是由命令行给定还是由目录中读取
main(argc, argv)
char *argv[];
{
int i;
register struct lbuf *ep, **ep1;
register struct lbuf **slastp;
struct lbuf **epp;
struct lbuf lb;
char *t;
int compar();
setbuf(stdout, stdbuf);
time(&lb.lmtime); //获取当前时间
year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 个月之前 */
if (--argc > 0 && *argv[1] == '-') {
argv++; //跳过程序文件名
while (*++*argv) switch (**argv) {//扫描命令行上第一个参数
case 'a': //输出所有目录项。如果没有该选项,则不输出 '.' 和 '..'。
aflg++;
continue;
case 's': //输出文件大小。文件名以字母顺序排列
sflg++;
statreq++;
continue;
case 'd': //用于目录参数,输出目录本身的信息,而不是目录的内容
dflg++;
continue;
case 'g': //用于 'ls -l',但输出组名而不是用户名
gflg++;
continue;
case 'l': //在第一列与文件名或长列表一起输出结点索引号
lflg++;
statreq++;
continue;
case 'r': //颠倒顺序排列。文件名以字母顺序或时间顺序进行排列
rflg = -1;
continue;
case 't': //以修改时间而不是文件名排列输出结果,最近修改的文件处于最前面
tflg++;
statreq++;
continue;
case 'u': //以访问时间而不是修改时间排列输出结果,与-t或 -l一起使用
uflg++;
continue;
case 'c': //使用索引结点的改变时间,而不是文件的修改时间。该选项与-t或-l一起使用。
cflg++;
continue;
case 'i': //在第一列与文件名或长列表一起输出节点索引号
iflg++;
continue;
case 'f': //强迫每个参数都当作目录读取,然后输出在每个目录槽中找到的
//文件名。该选项使-l、-r、-s和-t选项无效,但激活了-a选项
fflg++;
continue;
default: //忽略未知的选项字母
continue;
}
argc--; //扫描完第一个参数后,由于argv的移动,将argc减1
}
if (fflg) {
aflg++;
lflg = 0;//-f覆盖了-l、-s和-t选项
sflg = 0;
tflg = 0;
statreq = 0;
}
if(lflg) { //打开口令或组文件
t = "/etc/passwd";
if(gflg) //V7 ls命令仅显示用户和组信息中的一项
t = "/etc/group";
pwdf = fopen(t, "r");
}
if (argc==0) {//如果没有指定参数,则使用当前目录
argc++;
argv = &dotp - 1; //减1 是为了对下面的第139行'++argv'进行弥补
}
for (i=0; i < argc; i++) { //获得每个文件信息
if ((ep = gstat(*++argv, 1))==NULL)//gstat的第二个参数表示如果为1则文件
//由命令行参数给定,否则为假
continue;
ep->ln.namep = *argv; //获得文件名
ep->lflags |= ISARG; //加入ISARG位,用于后面判断文件是由命令行给定还是由
//目录读取
}
qsort(firstp, lastp - firstp, sizeof *lastp, compar);//对文件进行排序,这是个
//库中的排序函数
slastp = lastp; //将lastt当前值保存在slastp中
for (epp=firstp; epp<slastp; epp++) {//对数组的每个元素进行循环以适当的方式
//输出文件或目录信息
ep = *epp;
if (ep->ltype=='d' && dflg==0 || fflg) {//如果文件类型为目录并且未提供-d
//选项或提供了-f选项,则ls必须读取该目录而不是输出该目录本身的信息
if (argc>1)//如果命令行提供了多个文件则输出目录名和一个冒号
printf("\n%s:\n", ep->ln.namep);
lastp = slastp; //重设lastp
readdir(ep->ln.namep);
//flist数组作为一个两层的文件名堆栈。命令行参数通过slastp-1保存在flist中,当readdir
//读取目录的时候它将该目录内容的struct lbuf结构置于该堆栈之上,由slastp开始直到lastp。
if (fflg==0)//如果-f选项无效,则对子目录项进行排序。
qsort(slastp,lastp - slastp,sizeof *lastp,compar);
if (lflg || sflg)//输出目录中文件占用的块的总数用于-l或-s选项
printf("total %D\n", tblocks);//%D相当于现在的%ld
for (ep1=slastp; ep1<lastp; ep1++)//输出子目录每个文件的信息。
pentry(*ep1); //只深入到目录树的下一层,它没有用递归选项
} else
pentry(ep);
}
exit(0);
}
pentry(ap) //输出关于文件的信息函数
struct lbuf *ap;
{
struct { char dminor, dmajor;}; //这个变量未被使用!
register t;
register struct lbuf *p;
register char *cp;
p = ap;
if (p->lnum == -1)//如果为真则 struct lbuf是无效的。返回。
return;
if (iflg)
printf("%5u ", p->lnum); //索引节点号
if (sflg)
printf("%4D ", nblock(p->lsize));//以块为单位的文件大小
if (lflg) { //以长格式输出
putchar(p->ltype);//输出文件类型
pmode(p->lflags);//输出权限
printf("%2d ", p->lnl);
t = p->luid;
if(gflg)
t = p->lgid;
if (getname(t, tbuf)==0)
printf("%-6.6s", tbuf); //输出用户或组
else
printf("%-6d", t);
if (p->ltype=='b' || p->ltype=='c')//设备:主设备号和从设备号
printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize));
else
printf("%7ld", p->lsize); //以字节为单位的文件大小
cp = ctime(&p->lmtime);
if(p->lmtime < year) //修改时间
printf(" %-7.7s %-4.4s ", cp+4, cp+20); else//如果早于六个月之前则程序
//输出月、日、年否则输出月、日和时间
printf(" %-12.12s ", cp+4);
}
if (p->lflags&ISARG) //文件名。对于命令行参数,是一个以'\0'结尾的字符串可以
//使用%s
printf("%s\n", p->ln.namep);
else//对于从目录中读取的文件,可能并非以空字符结尾,因此必须使用确切精度的格式字符串%.14s
printf("%.14s\n", p->ln.lname);
}
getname(uid, buf)//将用户ID或组ID转换为相应的用户名和组名。
int uid;
char buf[];
{
int j, c, n, i;
if (uid==lastuid)//如果为真表示测试成功,返回
return(0);
if(pwdf == NULL) //安全检查
return(-1);
rewind(pwdf); //由文件内容的起始位置开始
lastuid = -1;
do {
i = 0; //buf数组中的索引
j = 0; //行中的计数器 ,记录当前遇到的冒号数:如果是名称则为0,如果是ID则为2。
n = 0; //转换数字值
while((c=fgetc(pwdf)) != '\n') {//读取各行
if (c==EOF)
return(-1);
if (c==':') { //对成员记数
j++;
c = '0';
}
if (j==0) //第一个成员为名称
buf[i++] = c;
if (j==2) //第三个成员为数字ID
n = n*10 + c - '0';
}
} while (n != uid); //一直进行搜索直到找到ID
buf[i++] = '\0';
lastuid = uid;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -