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

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 822 10:43 /dev
所以unlink(path)失败
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值