UNIX环境高级编程习题答案——第四章

tech2022-09-18  94

4.1 用stat函数替换图4-3程序中的lstat函数,如若命令行参数之一是符号链接,会发生什么变化?

会输出符号链接所指向文件的文件类型。

4.2 如果文件模式创建屏蔽字是777(八进制),结果会怎样?用shell的umask命令验证该结果

如果创建的是目录,那么该目录的用户、组和其他人均无法访问目录,在目录下创建或删除文件,无法搜索目录下的文件。 如果创建的是文件,那么该文件的用户、组和其他人均无法读、写和执行该文件。

4.5 4.12节中讲到一个普通文件的长度可以为0,同时我们又知道st_size字段是为目录或符号链接定义的,那么目录和符号链接的长度是否可以为0?

目录长度从来不会是0,因为它总是包含 . 和 .. 项。 因为路径名至少包含一个字符,所以符号链接长度也不会是0。

4.6 编写一个类似cp(1)程序,它复制包含空洞的文件,但不将字节0写到输出文件中去。

/************************************************************************* > File Name: test4_6.c > Author: Elliot > Created Time: Mon 14 Aug 2017 10:26:02 AM CST ************************************************************************/ #include "apue.h" #include <fcntl.h> #include <unistd.h> int main(int argc, char * argv[]) { int fdr; int fdw; int ch; if (argc != 3) err_quit("Usage: ./test4_6 <srcfile> <dstfile>"); if ((fdr = open(argv[1], O_RDONLY)) < 0) err_sys("Open %s: error", argv[1]); if ((fdw = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_MODE)) < 0) err_sys("Open %s: error", argv[2]); while(read(fdr, &ch, 1) == 1) { if(ch == '\0') continue; if (write(fdw, &ch, 1) != 1) err_sys("Write to %s: error!", argv[2]); } exit (0); }

4.7 在4.12节ls命令的输出中,core和core.copy的访问权限不同,如果创建两个文件的umask没有变,说明为什么会发生这种差别。

cat命令程序中调用了程序umask,而不是使用了shell的umask来创建文件。

4.8 在运行图4-16的程序时,使用了df(1)命令来检查空闲的磁盘空间。为什么不使用du(1)命令?

du命令查看的是磁盘占用空间的大小,创建的新文件并没有写入内容,所以占用磁盘空间大小为0。 df命令查看的是磁盘最大可用空间,即以使用数据块为单位进行统计,尽管新文件没有写入内容,但是占据了一定数量的数据块。

4.9 图4-20中显示unlink函数会修改文件状态更改时间,这是怎样发生的?

unlink会修改i节点的引用次数,所以会修改文件状态更改时间。

4.10 4.22节中,系统对可打开文件数的限制对myftw函数会产生什么影响?

用opendir打开一个目录后,递归函数调用dopath。假设opendir使用一个文件描述符,并且只有在处理完目录后才调用closedir释放描述符,这就意味着每次降一级就要使用另一描述符。所以进程最大描述符数就限制了我们可以遍历的文件系统树的深度。

4.11 在4.22节中的myftw从不改变其目录,对这种处理方法进行改动:每次遇到一个目录就用其调用chdir,这样每次调用lstat时就可以使用文件名而非路径名,处理完所有的目录项后执行chdir(“..”)。比较这种版本的程序和书中程序的运行时间

/************************************************************************* > File Name: ins4_22.c > Author: Elliot > Created Time: Sun 13 Aug 2017 03:53:05 PM CST ************************************************************************/ /* The program of document traversal */ /* Before you complie ins4_22.c, you must annotation error.c in apue.h * and copy error.c 、pathallocate.c to this directory(error.c in Linux /usr/include/error.c). * Complie : gcc ins4_22.c error.c pathallocate.c -o ins4_22 */ #include "apue.h" #include <dirent.h> #include <limits.h> #include <unistd.h> #include <time.h> /* function type that is called for each filename */ typedef int Myfunc(const char *, const struct stat *, int); static Myfunc myfunc; static int myftw(char *, Myfunc *); static int dopath(Myfunc *); static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot; int main(int argc, char *argv[]) { double whole; clock_t str,end; int ret; str = clock(); if (argc != 2) err_quit("usage: ftw <starting-pathname>"); ret = myftw(argv[1], myfunc); ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock; if (ntot == 0) ntot = 1; /* avoid divide by 0; print 0 for all counts */ printf("regular files = %7ld, %5.2f %%\n", nreg, nreg * 100.0 / ntot); printf("directories = %7ld, %5.2f %%\n", ndir, ndir * 100.0 / ntot); printf("block special = %7ld, %5.2f %%\n", nblk, nblk * 100.0 / ntot); printf("char special = %7ld, %5.2f %%\n", nchr, nchr * 100.0 / ntot); printf("FIFOs = %7ld, %5.2f %%\n", nfifo, nfifo * 100.0 / ntot); printf("symbolic links = %7ld, %5.2f %%\n", nslink, nslink * 100.0 / ntot); printf("sockets = %7ld, %5.2f %%\n", nsock, nsock * 100.0 / ntot); end = clock(); whole = (double)(end - str) / CLOCKS_PER_SEC; printf("test4_11 costs : %f second\n", whole); exit(ret); } /* * Descend through the hierachy, starting at "pathname". * The caller's func() is called for every file. */ #define FTW_F 1 /* file other than directory */ #define FTW_D 2 /* directory */ #define FTW_DNR 3 /* directory that can't be read */ #define FTW_NS 4 /* file that we can't stat */ static char * filename; /* contains full pathname for every file */ static size_t pathlen; static int /* we return whatever func() returns */ myftw(char *pathname, Myfunc *func) { filename = path_alloc(&pathlen); /* malloc PATH_MAX+1 bytes */ /* ({Flgure 2.16}) */ if (pathlen <= strlen(pathname)) { pathlen = strlen(pathname) * 2; if ((filename = realloc(filename, pathlen)) == NULL) err_sys("realloc failed"); } strcpy(filename, pathname); return(dopath(func)); } /* * Descend through the hirearchy, starting at "filename". * If "filename" is anything other than a directory, we lstat() it, * call func(), and return, For a directory, we call ourself * recursively for each name in the directory. */ static int /* we return whatevery func() returns */ dopath(Myfunc *func) { struct stat statbuf; struct dirent *dirp; DIR *dp; int ret, n; if (lstat(filename, &statbuf) < 0) /* stat error */ return (func(filename,&statbuf, FTW_NS)); if (S_ISDIR(statbuf.st_mode) == 0) /* not a directory */ return (func(filename, &statbuf, FTW_F)); /* * It's a directory, First call func() for the directory, * then process each filename in the directory. */ if ((ret = func(filename, &statbuf, FTW_D)) != 0) return(ret); n = strlen(filename); if (n + NAME_MAX + 2 > pathlen) /* expand path buffer */ { pathlen *= 2; printf("realloc\n"); if ((filename = realloc(filename, pathlen)) == NULL) err_sys("realoc failed"); } if ((dp = opendir(filename)) == NULL) /* can't read directory */ return(func(filename, &statbuf, FTW_DNR)); if (chdir(filename) < 0) err_sys("chdir %s error", filename); while ((dirp = readdir(dp)) != NULL) { if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) continue; /* ignore dot and dot-dot */ filename = dirp->d_name; if ((ret = dopath(func)) != 0) /* recursive */ { break; /* time to leave */ } } if (chdir("..") < 0) err_sys("chdir .. error"); if (closedir(dp) < 0) err_ret("can't close directory %s", filename); return(ret); } static int myfunc(const char *pathname, const struct stat *statptr, int type) { switch (type) { case FTW_F: switch (statptr->st_mode & S_IFMT) { case S_IFREG: nreg++; break; case S_IFBLK: nblk++; break; case S_IFCHR: nchr++; break; case S_IFIFO: nfifo++; break; case S_IFLNK: nslink++; break; case S_IFSOCK: nsock++; break; case S_IFDIR: /* directories should have type = FTW_D */ err_dump("for S_IFDIR for %s", pathname); } break; case FTW_D: ndir++; break; case FTW_DNR: err_ret("can't read directory %s", pathname); break; case FTW_NS: err_ret("stat error for %s", pathname); break; default: err_dump("unknow type %d for pathname %s", type, pathname); } return (0); }

4.12 每个进程都有一个根目录用于解析绝对路径名,可以通过chroot函数改变根目录。在手册中查阅此函数。说明这个函数什么时候有用?

chroot函数被因特网文件传输协议(Internet File Transfer Protocol, FTP)程序用于辅助安全性。系统中没有账户的用户(也称匿名FTP)放在一个单独的目录下,利用chroot讲此目录当做新的根目录,就可以阻止用户访问此目录以外的文件。 chroot也用于另一台机器上构造一个文件系统层次结构的副本,然后修改此副本,不会更改原来的文件系统。这可用于测试新软件包的安装。 chroot只能由超级用户执行,一旦更改了一个进程的根,该进程及后代进程就再也不能恢复至原先的根。

4.13 如何设置两个时间值中的一个来使用utimes函数。

首先调用stat函数取得文件的3个是时间值,然后调用utimes设置期望的值,最近访问utimes时我们不希望改变的值应当是stat中相应的值。

4.14 有些版本finger(1)命令输出“New mail received…”和“unread since…”,其中…表示相应的日期和时间。程序是如何决定这些日期和时间的。

finger(1)对邮箱调用stat函数,最近一次的修改时间是上一次接收邮件的时间,最近一次访问时间是上一次读邮件的时间。

4.16 UNIX系统对目录树的深度有限制吗?编写一个程序循环,在每次循环中,创建目录,并将该目录更改为工作目录。确保叶节点的绝对路径名的长度大于系统的PATH_MAX限制。可以调用getcwd得到目录的路径名吗?标准UNIX系统工具是如何处理长路径名的?对目录可以使用tar或cpio命令归档吗?

/************************************************************************* > File Name: test4_16.c > Author: Elliot > Created Time: Mon 14 Aug 2017 04:51:21 PM CST ************************************************************************/ #include "apue.h" #include <fcntl.h> #define DEPTH 1000 /* directory depth */ #define STARTDIR "/tmp" #define NAME "alonglonglonglonglonglonglonglonglonglongname" #define MAXSZ (10*8192) int main(void) { int i; size_t size; char *path; if (chdir(STARTDIR) < 0) err_sys("chdir error"); for (i = 0; i < DEPTH; i++) { if (mkdir(NAME, DIR_MODE) < 0) err_sys("mkdir failed, i = %d", i); if (chdir(NAME) < 0) err_sys("chdir faild, i = %d", i); } if (creat("afile", FILE_MODE) < 0) err_sys("creat error"); /* * The deep directory is created, with a file at the leaf. * Now let's try to obtain its pathname */ path = path_alloc(&size); for (; ;) { if (getcwd(path, size) != NULL) break; else { err_ret("getcwd failed, size = %ld", (long)size); size += 100; if (size > MAXSZ) err_quit("giving up"); if ((path = realloc(path, size)) == NULL) err_sys("realloc error"); } } printf("length = %ld\n%s\n", (long)strlen(path), path); }

4.17 3.16节中描述了/dev/fd特征。如果每个用户都可以访问这些文件,则其访问权限必须为rw-rw-rw-。有些程序创建输出文件时,先删除该文件以确保该文件名不存在,忽略返回码。

unlink(path); if ((fd = creat(path, FILE_MODE)) < 0) err_sys(...); 如果path是/dev/fd1/,会出现什么情况? 因为/dev目录关闭了其他用户的写权限: $ ls -ld /dev drwxr-xr-x 21 root root 3500 8月 22 10:43 /dev 所以unlink(path)失败

 

 

 

 

 

 

 

最新回复(0)