📄 新建 文本文档 (2).txt
字号:
return(0);
}
long
nblock(size) //返回文件使用了多少磁盘块。V7块大小为512字节——物理磁盘分区大小
long size;
{
return((size+511)>>9);//右移9位相当于除以512,从而获得块数。即使文件只有一个字节
//也要占用一个磁盘块。但是1/512的结果为0。所以表达式为'size+511'保证了得到正确的块数
}
//对要检查的权限位以及相应的输出字符进行编码。文件模式中的每个输出字符都有一个数组。
int m1[] = { 1, S_IREAD>>0, 'r', '-' };
int m2[] = { 1, S_IWRITE>>0, 'w', '-' };
int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
int m4[] = { 1, S_IREAD>>3, 'r', '-' };
int m5[] = { 1, S_IWRITE>>3, 'w', '-' };
int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
int m7[] = { 1, S_IREAD>>6, 'r', '-' };
int m8[] = { 1, S_IWRITE>>6, 'w', '-' };
int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' };
int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
pmode(aflag)
{
register int **mp;
flags = aflag;//得到文件权限位(mode_t类型)
for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];)
select(*mp++);//这里以及下面都使用了'++',目的是为了当(权限,字符)对的第一个
//元素在flags中未找到的时候跳过数组中的(权限,字符)对。
//这段代码设计的很精巧、幽雅值得仔细研究
}
select(pairp)//从权限,字符数组中选择flags中相应的元素
register int *pairp;
{
register int n;
n = *pairp++;
while (--n>=0 && (flags&*pairp++)==0)
pairp++;
putchar(*pairp);
}
char *
makename(dir, file) //连接由斜杠分割的目录名和文件名并产生一个字符串
char *dir, *file;
{
static char dfile[100];
register char *dp, *fp;
register int i;
dp = dfile;
fp = dir;
while (*fp)
*dp++ = *fp++;
*dp++ = '/';
fp = file;
for (i=0; i<DIRSIZ; i++)
*dp++ = *fp++;
*dp = 0;
return(dfile);
}
readdir(dir) //读取命令行指定的目录内容
char *dir;
{
static struct direct dentry;
register int j;
register struct lbuf *ep;
if ((dirf = fopen(dir, "r")) == NULL) {//打开用于读取的目录
printf("%s unreadable\n", dir);
return;
}
tblocks = 0;//将全局变量清零。
for(;;) {
if (fread((char *)&dentry, sizeof(dentry), 1, dirf) != 1)
//读取目录项并将其添加到flist数组中
break;
if (dentry.d_ino==0
|| aflg==0 && dentry.d_name[0]=='.' && (dentry.d_name[1]=='\0'
|| dentry.d_name[1]=='.' && dentry.d_name[2]=='\0'))
continue;//跳过不感兴趣的目录项
ep = gstat(makename(dir, dentry.d_name), 0);//第二个参数为0,表明参数不是
//来自命令行,它更新lastp和flist
if (ep==NULL)
continue;
if (ep->lnum != -1)
ep->lnum = dentry.d_ino;//保存索引节点号
for (j=0; j<DIRSIZ; j++)
ep->ln.lname[j] = dentry.d_name[j];//保存文件名
}
fclose(dirf);
}
struct lbuf *
gstat(file, argfl)//获得和存储文件信息的核心函数
char *file;
{
extern char *malloc();
struct stat statb;
register struct lbuf *rep;
static int nomocore;
if (nomocore) //已经耗尽内存
return(NULL);
rep = (struct lbuf *)malloc(sizeof(struct lbuf));
if (rep==NULL) {
fprintf(stderr, "ls: out of memory\n");
nomocore = 1;
return(NULL);
}
if (lastp >= &flist[NFILES]) {//检查是否给定文件太多
static int msg;
lastp--;
if (msg==0) {
fprintf(stderr, "ls: too many files\n");
msg++;
}
}
*lastp++ = rep; //填充文件信息
rep->lflags = 0;
rep->lnum = 0;
rep->ltype = '-'; //缺省文件类型
if (argfl || statreq) {
if (stat(file, &statb)<0) {
printf("%s not found\n", file);
statb.st_ino = -1;
statb.st_size = 0;
statb.st_mode = 0;
if (argfl) {
lastp--;
return(0);
}
}
rep->lnum = statb.st_ino; //stat()调用成功,拷贝信息
rep->lsize = statb.st_size;
switch(statb.st_mode&S_IFMT) {
case S_IFDIR:
rep->ltype = 'd';
break;
case S_IFBLK:
rep->ltype = 'b';
rep->lsize = statb.st_rdev;
break;
case S_IFCHR:
rep->ltype = 'c';
rep->lsize = statb.st_rdev;
break;
}
rep->lflags = statb.st_mode & ~S_IFMT;
rep->luid = statb.st_uid;
rep->lgid = statb.st_gid;
rep->lnl = statb.st_nlink;
if(uflg)
rep->lmtime = statb.st_atime;
else if (cflg)
rep->lmtime = statb.st_ctime;
else
rep->lmtime = statb.st_mtime;
tblocks += nblock(statb.st_size);
}
return(rep);
}
compar(pp1, pp2)//比较函数,用于排序函数qsort()的调用
struct lbuf **pp1, **pp2;
{
register struct lbuf *p1, *p2;
p1 = *pp1;
p2 = *pp2;
//下面的代码中返回负数表示第一个文件相对于第二个文件应该位于数组的前面,0表示
//两个文件相等,1表示第二个文件相对于第一个文件应该位于数组的前面
if (dflg==0) {//如果必须读取目录
if (p1->lflags&ISARG && p1->ltype=='d') {//p1是一个命令行参数且p1是一个目录
if (!(p2->lflags&ISARG && p2->ltype=='d'))//p2不是一个命令行参数且p2不是一个目录
return(1);//第一种情况在第二种情况之后
} else {//p1不是一个命令行目录
if (p2->lflags&ISARG && p2->ltype=='d')//p2是一个命令行参数且p2是一个目录
return(-1);//第一种情况在第二种情况之前
}
}
if (tflg) {//排序是基于时间的
if(p2->lmtime == p1->lmtime)//p2的时间等于p1的时间
return(0);
if(p2->lmtime > p1->lmtime)//p2的时间大于p1的时间
return(rflg);//返回rflg的值(正或负)
return(-rflg);//p2的时间小于p1的时间
}
//返回相乘的结果
return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname,
p2->lflags&ISARG? p2->ln.namep: p2->ln.lname));
}
/****************************************
移植性问题。
若将V7 的ls 命令移植到现代操作系统中会遇到些问题,使其无法编译通过。
①。V7 的ls 中定义的函数如 readdir()、select()等函数会与系统库函数发生冲突,即名字
污染。移植的时候,要把这些函数改名方可。
②。V7 的ls 中读目录所使用的函数readdir()使用fopen()、fread()函数进行读目录,这与
现代操作系统中读取目录信息发生冲突,使读目录无法正常工作。(现代Linux中使用
opendir()、readdir()(与本程序的版本不同,它是一个系统调用))
③。V7 的ls中目录名的长度限定在14个字符。即#define DIRSIZ 14 但现代操作系统中没有
这个定义。移植后,编译出错。
④。而且这个DIRSIZ 对于现代所允许的目录名长度显得太小。
⑤......
......
等等
本文把V7 的ls 移植到REDHAT 9中出现了上述问题。
移植后的相关修改。
1。把readdir()、select()函数改成其他和系统调用不冲突的名字。
2。在程序开始处添加 #define DIRSIZ 14
3。在原readdir()函数内部添加或修改
static struct direct *dentry;
.....
DIR *dp;
将 if ((dirf = fopen(dir, "r")) == NULL) {//打开用于读取的目录
printf("%s unreadable\n", dir);
return;
}
改成 if(( dp = opendir(dir)) == NULL) {
printf("%s unreadable\n", dir);
return;
}
将 if (fread((char *)&dentry, sizeof(dentry), 1, dirf) != 1)
改成 if( dentry = readdir(dp) == NULL )
把所有的dentry. 改成 dentry->
这样初步修改后,程序基本可以正常运行,只是对于目录名超过14个字符的,无法正常读取
等等。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -