apue第4章习题
4.1 用 stat 函数替换图 4-3 程序中的 lstat函数,如若命令行残数之一是符号链接,会发生什么变化?
stat不支持链接,如果有参数是链接符号,会显示链接后的文件属性。
4.2 如果文件模式创建屏蔽字 777 (八进制),结果会怎样?用shell的umask命令验证该结果
pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ vim ex4-2.c pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ gcc ex4-2.c pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ./a.out pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ls 4-12.c 4-21.c 4-23.c 4-25.c 4-8.c a.out ex4-2_bar ex4-2_foo myfile times 4-16.c 4-22.c 4-24.c 4-3.c 4-9.c changemod ex4-2.c foo tags pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ls -la ex4-2_bar ex4-2_foo ---------- 1 pi pi 0 Dec 1 08:52 ex4-2_bar -rw-rw-rw- 1 pi pi 0 Dec 1 08:52 ex4-2_foo
会把所有的位都屏蔽掉
4.3 关闭一个你所拥有文件的用户读权限,将导致拒绝你访问自己的文件,对此进行验证。
pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ chmod u-rw ex4-2_foo pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ cat ex4-2_foo cat: ex4-2_foo: Permission denied
4.4 创建文件foo和bar后,运行图4-9的程序,讲发生什么情况?
pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ./a.out pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ls -l foo bar -rw------- 1 pi pi 0 Dec 1 09:25 bar -rw-rw-rw- 1 pi pi 0 Dec 1 09:25 foo pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ chmod a-r foo bar pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ls -l foo bar --w------- 1 pi pi 0 Dec 1 09:25 bar --w--w--w- 1 pi pi 0 Dec 1 09:25 foo pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ./a.out pi@raspberrypi:~/chen_DIR/APUE/chapter_4 $ ls -l foo bar --w------- 1 pi pi 0 Dec 1 09:26 bar --w--w--w- 1 pi pi 0 Dec 1 09:26 foo
文件的权限没有变,但是文件内容什么的修改时间都被改了。
4.5 4.12节中讲到一个普通文件的大小可以为0,同时我们又知道st_size字段是为目录或符号链接定义的,那么目录和符号链接的长度是否可以为0?
目录的长度从来不会是0,因为它总是包含 . 和 .. 两项。符号链接的长度指其路径名包含的字符数,由于路径名中至少有一个字符,所以长度也不为0。
4.6 编写一个类似cp(1)的程序,他复制包含空洞的文件,但不将字节0写到输出文件中去。
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #define BUF_SIZE 4096 int main(int argc, char *argv[]) { char *filePathFrom; char *filePathTo; int fdFrom, fdTo; int have_holes, byte_count, res, current_position; char buff[BUF_SIZE]; struct stat st; if(argc !=3 || !argv[1] || !argv[2]) { fprintf(stderr, "Usage: %s <source file path> <target file path>\n", argv[0]); exit(1); } filePathFrom = argv[1]; filePathTo = argv[2]; if((fdFrom = open(filePathFrom, O_RDWR)) < 0) { fprintf(stderr, "open path from error"); exit(1); } if(fstat(fdFrom, &st) != 0) fprintf(stderr, "stat error"); else { if(S_ISREG(st.st_mode) && st.st_size > 512 * st.st_blocks) { have_holes = 1; printf("%s is a sparse-block file!\n", filePathFrom); } else { have_holes = 0; printf("%s is not a sparse-block file!\n", filePathFrom); } } if((fdTo = open(filePathTo, O_RDWR|O_APPEND|O_CREAT|O_TRUNC, 0666)) < 0) { fprintf(stderr, "open path to error"); exit(1); } memset(buff, '\0', BUF_SIZE); if((res = read(fdFrom, buff, BUF_SIZE)) < 0) { fprintf(stderr, "fdFrom read error"); exit(1); } if(have_holes) { byte_count = 0; for(current_position = 0;current_position < res; current_position++) { if(buff[current_position] != 0) { buff[byte_count] = buff[current_position]; byte_count++; } } } else byte_count = res; if((res = write(fdTo, buff, byte_count)) < 0) { fprintf(stderr, "fdTo write error"); exit(1); } close(fdFrom); close(fdTo); }
4.7 在4.12节ls命令的输出中,core和core.copy的访问权限不同,如果创建两个文件时umask没有变,说明为什么会发生这种差别。
当创建新的core文件时,内核对其访问权限有一个默认设置,在本例中是rw-r--r--。这一默认值可能会也可能不会被umask的值修改。shell对创建的重定向的新文件也有一个默认的访问权限,本例中为rw-rw-rw-,这个值总是被当前的umask修改,在本例中umask为02.
4.8 在运行图4-16的程序时,使用了df(1)命令来检查空闲的磁盘空间。为什么不使用du(1)命令?
不能使用du的原因是它需要文件名,如
du tempfile或目录名,如
du .
只有当unlink函数返回时才释放tempfile的目录项,du .命令没有计算仍然被tempfile占用空间。本例中只能使用df命令查看文件系统中实际可用的空闲空间。
4.9 图4-20中显示unlink函数会修改文件状态更改时间,这是怎样发生的?
如果被删除的链接不是该文件的最后一个链接,则不会删除该文件。此时,文件的状态更改时间被更新。但是,如果被删除的链接是最后一个链接,则该文件将物理删除。这时再去更新文件的状态更改时间就没有意义,因为包含文件所有信息的i借点将会随着文件的删除而被释放。
4.10 4.22节中,系统对可打开文件数的限制对myftw函数会产生什么影响?
用opendir打开一个目录后,递归调用函数dopath。假设opendir使用一个文件描述符,并且只有在处理完目录后才调用closedir释放描述符,这就意味着每次降一级就要使用另外一个描述符。所以进程可以打开的最大描述符就限制了我们可以遍历的文件系统数的深度。single Unix sepcification的XSI扩展中说明的ftw允许调用者指定使用的描述符,这隐含着可以关闭描述符并且重用它们。
4.11 在4.22节中的myftw从不改变其目录,对这种处理方法进行改动;每次遇到一个目录就调用chdir,这样每次调用lstat时就可以使用文件名而非路径名,处理完所有的目录项后执行chdir("..")。比较这种版本的程序和书中程序的运行时间。
#include "apue.h" #include <dirent.h> #include <limits.h> #include "../chapter_2/2-16.c" /* 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[]) { int ret; if(argc != 2) err_quit("usage: ftw <starting-pathname>"); ret = myftw(argv[1], myfunc); /* does it all */ ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock; if(ntot == 0) ntot = 1; 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); exit(ret); } #define FTW_F 1 #define FTW_D 2 #define FTW_DNR 3 #define FTW_NS 4 static char *fullpath; static char *filename; static size_t pathlen; static int myftw(char *pathname, Myfunc *func) { filename = path_alloc(&pathlen); if(pathlen <= strlen(pathname)) { pathlen = strlen(pathname) * 2; if((filename = realloc(filename, pathlen)) == NULL) err_sys("realloc failed."); } strcpy(filename, pathname); return (dopath(func)); } static int dopath(Myfunc *func) { struct stat statbuf; struct dirent *dirp; DIR *dp; int ret, n; if(lstat(filename, &statbuf) < 0) return(func(filename, &statbuf, FTW_NS)); if(S_ISDIR(statbuf.st_mode) == 0) return(func(filename, &statbuf, FTW_F)); if((ret = func(filename, &statbuf, FTW_D)) != 0) return(ret); n = strlen(filename); if(n + NAME_MAX + 2 > pathlen) { pathlen *= 2; if((filename = realloc(filename, pathlen)) == NULL) err_sys("realloc failed"); } //filename[n++] = '/'; //filename[n] = 0; if((dp = opendir(filename)) == NULL) 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; filename = dirp->d_name; if((ret = dopath(func)) != 0) break; } 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: 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("unknown type %d for pathname %s", type, pathname); } return(0); }
4.12 每个进程都有一个根目录用于解析绝对路径名,可以通过chroot函数改变根目录。在手册中查询次函数。说明这个函数什么时候有用
chroot函数被因特网文件传输协议(Internet File Transfer Protocal,FTP)程序用于辅助安全性。系统中没有账户的用户(也称为匿名FTP)放在一个单独的目录下,利用chroot将此目录当作新的根目录,就可以阻止用户方位此目录以外的文件。
chroot也用于在另一台机器上构造一个文件系统层次结构的副本,然后修改此副本,不会更改原来的文件系统。这可用于测试新软件包的安装。
chroot只能由超级用户执行,一旦更改了一个进程的根,该进程及其后代进程就再也不能回复至原先的根。