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)失败