unix环境高级编程第四章习题的一些拙见

来源:互联网 发布:慈溪行知职高老师 编辑:程序博客网 时间:2024/05/24 16:15

重新开始更新第四章的内容,每天一点点。

apue4.1:

由于在这里lstat是不跟随符号文件的,而stat是跟随符号文件的,这样一来,如果使用stat,而不使用lstat那么就无法观察到符号文件。在书上4.3姐中有提到。

apue4.2:

首先我在ubuntu的shell上查看原来的umask是多少,结果是0002,这里touch一个文件是不确定的,但是其他者的权限中写的权限一定是没有的。因为创建一个文件所拥有的权限不光与umask有关还与应用程序自身在创建的时候使用的参数有关系。

这里我在一个拥有权限的文件夹中创建文件,(用touch)这样所显示的权限是-rw-rw-r--。之后我再用umask将文件的umask改为777,这时候创建一个文件权限应该是----------

apue4.3:

这个真要截图吗?我真懒XD

-----------------------------------------------------------------------------------------------------------------------------分割线2016.6.5

apue4.4:

这个做一个简单的实验就可以了,在运行这个程序之前我先创建了foo和bar文件,同时两个文件的权限都是-rw-r--r--,然后我再运行这个程序,我发现这两个文件的权限并没有发生变化,当我再运行这个程序的时候创建了两个文件,这两个文件都是和程序运行之后所期望的权限那样,这里可以知道,creat函数发现文件存在之后就不再管后面的操作了!

apue4.5:

这里我们知道目录中包含的是这个目录中所包含的文件,很显然目录也是一种文件,其中目录中必然包含.和..这两个文件,所以不可能为0,而链接文件的字节大小指的是所链接文件名字的大小,由于文件的名字不能为0,所以这里符号文件的大小也不能为0

apue4.6:

又到了写代码的时间,啊哈哈。我已经有思路了,但是这里我只实现一个比较简单的版本,只能针对树上的版本,这里对很多的细节我就不再追究,主要认清楚思路,和这里的性质。明天上代码!

————————————————————————————————————————分割线2015.6.24

来上代码了,今天早上没事花了一个半小时,把代码从理论上改的比较好了,应该是可以适应很多情况了,当然我没有经过很多测试XD。。。

#include "apue.h"#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#define BUF_SIZE 1024#define TYPE_ZERO 0#define TYPE_CHAR 1typedef struct node {    int type;    int start[BUF_SIZE];    int length[BUF_SIZE];    int number;}Node;void search (char *buf , int n , Node *node_char , Node *node_zero) ;int init_node (Node *N , int n) ;char buf[BUF_SIZE];long off = 0;int main () {    int i;    int n;    int fd_w , fd_r;    Node *node_zero = (Node *) malloc (sizeof (Node));    Node *node_char = (Node *) malloc (sizeof (Node));    if ((fd_w = creat ("file.hole.backup" , FILE_MODE)) < 0)        err_sys ("creat error");    if ((fd_r = open ("file.hole" , O_RDONLY)) < 0)        err_sys ("open error");    while ((n = read (fd_r , buf , 1024)) > 0) {        search (buf , n , node_char , node_zero);        /*for (i = 0 ; i <= node_zero->number ; i++) {            printf ("node_zero->start[%d] = %d" , i , node_zero->start[i]);            printf ("node_zero->length[%d] = %d" , i , node_zero->length[i]);            printf ("\n");        }    }*/        if (node_char->number > node_zero->number) {            for (i = 0 ; i <= node_char->number-1 ; i++) {                if (write (fd_w , buf+node_char->start[i] , node_char->length[i]) < 0)                    err_sys ("write1 after search error");                if (lseek (fd_w , node_zero->length[i] , SEEK_CUR) < 0)                     err_sys ("lseek1 after search error");            }            if (write (fd_w , buf+node_char->start[node_char->number] , node_char->length[node_char->number])< 0 )                err_sys ("write2 after search error");        }else if (node_char->number < node_zero->number) {            for (i = 0 ; i <= node_zero->number-1 ; i++) {                if (lseek (fd_w , node_zero->length[i] , SEEK_CUR) < 0)                     err_sys ("lseek2 after search error");                if (write (fd_w , buf+node_char->start[i] , node_char->length[i]) < 0)                    err_sys ("write3 after search error");            }            if (lseek (fd_w , node_zero->length[node_zero->number] , SEEK_CUR) < 0)                err_sys ("lseek3 after search error");        }else if (node_zero->number == node_char->number) {            if (node_char->start[0] < node_zero->start[0]) {                for (i = 0 ; i <= node_char->number ; i++) {                    if (write (fd_w , buf+node_char->start[i] , node_char->length[i]) < 0)                        err_sys ("write4 after search error");                    if (lseek (fd_w , node_zero->length[i] , SEEK_CUR) < 0)                         err_sys ("lseek4 after search error");                }            }else if (node_zero->start[0] < node_char->start[0]) {                for (i = 0 ; i <= node_zero->number ; i++) {                    if (lseek (fd_w , node_zero->length[i] , SEEK_CUR) < 0)                         err_sys ("lseek5 after search error");                    if (write (fd_w , buf+node_char->start[i] , node_char->length[i]) < 0)                        err_sys ("write5 after search error");                }            }        }    }    if (n < 0)        err_sys ("read error");}void search (char *buf , int n , Node *node_char , Node *node_zero) {    int i;    int count = 0;    if (!(init_node (node_zero , 0)))        err_sys ("init_node node_zero error");    if (!(init_node (node_char , 1)))        err_sys ("init_node node_char error");    for (i = 0 ; i < n ; i++) {        if (i == 0) {            if (*buf != '\0') {                node_char->number++;                node_char->start[node_char->number] = 0;                node_char->length[node_char->number] = 1;            }else if (*buf == '\0') {                node_zero->number++;                node_zero->start[node_zero->number] = 0;                node_zero->length[node_zero->number] = 1;            }        }else if (i != 0) {            if (*(buf+i) == '\0' && *(buf+i-1) != '\0') {                node_zero->number++;                node_zero->start[node_zero->number] = i;                node_zero->length[node_zero->number] = 1;            }else if (*(buf+i) == '\0' && *(buf+i-1) == '\0') {                node_zero->length[node_zero->number]++;            }else if (*(buf+i) != '\0' && *(buf+i-1) == '\0') {                node_char->number++;                node_char->start[node_char->number] = i;                node_char->length[node_char->number] = 1;            }else if (*(buf+i) != '\0' && *(buf+i-1) != '\0') {                node_char->length[node_char->number]++;            }        }    }}int init_node (Node *N , int n) {    int i;    switch (n) {        case 0:            N->type = TYPE_ZERO;            N->number = -1;            break;        case 1:            N->type = TYPE_CHAR;            N->number = -1;            break;        default:            return 0;    }    for (i = 0 ; i < BUF_SIZE ; i++) {        N->start[i] = 0;        N->length[i] = 0;    }    return 1;}

这么长的代码,反正你让我看,我是不会看的,说一下主要的思路,因为要不能把空洞中的'\0'复制进去,但是可以利用即使是空洞也可以判断'\0',利用这点,判断读取的缓冲区中空洞的大小和数据的大小(数据是不会为'\0'的),利用一个数据结构记下来,然后判断如果是数据就直接往文件中写数据,如果是空洞就利用lseek的方法制造相应的空洞!这里非常有趣的一点是,即使是文件中的空洞部分,利用read函数的时候仍然是可以显示为'\0'的。这个题目很好的揭示了文件中的空洞的形成!虽然有点麻烦吧,但是代码敲的还是很爽的!

——————————————————————————————————————————分割线 2016.6.25
apue4.7:

文件最后的权限是依赖于两个原因的,其一是创建的时候进程给予其默认的权限,和umask的屏蔽作用。这里题目给出的前提是没有被umask修改,所以很显然内核和shell创建文件的时候给予文件默认的权限是不同的,而这个默认的权限和umask相互租用之后,变现出来的最后的文件权限也是不同的。

apue4.8:

这道题目还是很有意思的,首先复习一下文件系统的内容,首先一块硬盘被分为很多的文件系统,其中文件系统又被分为i节点数组,数据节点和目录节点,目录节点中记录着目录项,目录项记录着文件名(这里其实我也没有完全弄清楚,以后我会慢慢弄清楚的)和i节点的指针,通过这个指针去寻找相应的i节点,而i节点中记录这数据块。link(这里讨论硬链接)的机制就是创建一个目录项,指向i节点,这里允许多个目录项指向同一个 i节点!这里有一个特性,内核首先会检查文件被进程打开的数量,如果为0,在去检查链接数,如果两者都为0,那么内核就可以删除这个文件的内容。

具体到这个问题我们可以知道,unlink返回后文件的名字就不存在了,而du这个命令是依赖于文件的名字的(个人认为这个命令的实现并没有深入到底层),但是这个时候文件的内容没有被删除(因为进程还没有结束,在睡眠状态)这个时候就会有矛盾,然而df这个命令就不会有这个问题,它统计的是整个文件系统的内容,依赖于底层的!

————————————————————————————————————————————分割线2016.6.26

apue4.9:

我们知道文件一共有你三个时间atime,ctime,mtime,这三个时间分别是访问时间,状态修改时间,内容修改时间,访问时间更新发生在例如用cat这个文件,mtime的更新发生在修改文件的内容,ctime的更新发生在i节点的内容变化的时候,unlink的作用是解除目录项对i节点的指向,肯定会更新i节点内的计数,所以肯定会更新i节点的内容,因而这里也就改变了ctime。当然这里也需要考虑一下当解除的是最后一个指向的时候,并且打开文件的进程的为零的时候,i节点随着文件的删除而被释放就没有必要更新ctime。

apue4.10:

在unix世界的哲学就是一切都是文件,那么目录也就是文件,每打开目录其实就是相当于打开一个文件,那么这个进程就相当等于拥有了一个文件描述符,进程对最大文件描述符数量的限制也就对进程所能进入的文件树的层次进行了限制。

—————————————————————————————————————————————分割线2016.6.27

apue4.11:

这道题有意思的,用chdir的方式改变当前目录,再去用递归的方式解决,很遗憾个人的实力不够,不能写出作者那样精妙绝伦的递归,我个人的实现有不好的地方,代码中也没有进行错误检查,这到题目我花了很多时间想做到极致但是并没有成功,后来我把书上的dopath完全删除自己实现了一个chdir的方式,不足的地方是没有动态分配目录长度,不能对根目录进行递归。其他的和书上实现的结果是一致的。上代码吧:

#include "apue.h"#include <dirent.h>#include <limits.h>#include <sys/time.h>#define MAXSIZE 1000000typedef int Myfunc (const char* , const struct stat * , int);static Myfunc myfunc;static int dopath (Myfunc *);static long nreg , ndir , nblk , nchr , nfifo , nslink , nsock , ntot;static char fullpath[MAXSIZE];static size_t pathlen;static char childname[NAME_MAX] = ".";static int flag = 0;int main (int argc , char *argv[]) {    struct timeval time_a , time_b;    int ret;    if (argc != 2)         err_quit ("usage : ftw <starting-pathname>");    strcpy (fullpath , argv[1]);    chdir (fullpath);    if (gettimeofday (&time_a , NULL) < 0)        err_sys ("gettimeofday failed");    dopath (myfunc);    ntot = nreg + ndir + nblk + nfifo + nslink + nsock + nchr;    if (ntot == 0)        ntot = 1;    printf ("the regular file = %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);    if (gettimeofday (&time_b , NULL) < 0)        err_sys ("gettimeofday failed");    printf ("it takes %ld usec\n" , time_b.tv_usec - time_a.tv_usec);    exit (ret);}#define FTW_F 1#define FTW_D 2#define FTW_DNR 3#define FTW_NS 4static int dopath (Myfunc *func) {    struct stat statbuf;    struct dirent *dirp;    DIR *dp;    int ret , n_full , n_child;    char buf[1024];        if (lstat (fullpath , &statbuf) < 0)        return(func (fullpath , &statbuf , FTW_NS));    if (S_ISDIR (statbuf.st_mode) == 0)        return (func(fullpath , &statbuf , FTW_F));    else        flag = 1;    if ((ret = func (fullpath , &statbuf , FTW_D)) != 0)        return (ret);    chdir (fullpath);    getcwd (fullpath , MAXSIZE);    n_full = strlen (fullpath);    fullpath[n_full++] = '/';    fullpath[n_full] = 0;    dp = opendir (fullpath);    while ((dirp = readdir (dp)) != NULL) {        if (strcmp (dirp->d_name , ".") == 0 || strcmp (dirp->d_name , "..") == 0)            continue;        strcpy (&fullpath[n_full] , dirp->d_name);        if ((ret = dopath (func)) != 0)             break;    }    chdir ("..");    return (0);}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 dirctory %s" , pathname);            break;        case FTW_NS:            err_ret ("stat error for %s" , pathname);            break;        default:            err_dump ("unkown type");    }    return (0);}

就是这样,如果有大神愿意改一下使得完美甚好!

——————————————————————————————————————————分割线2016.6.29

apue4.12:

这个函数只有超级用户才能使用,它改变当前的进程的根目录,一般用在服务器进程,使得系统更加的安全,只能访问特定路径以下的文件,而不能访问路径以上的文件,同时这个函数一旦生效对于这个进程来说就不能再切换到其他目录作为根目录。

apue4.13:

我们查看utimes的函数原型,我们可以看到第一个参数是pathname,utimes会对这个pathname进行操作将其中的atime和mtime修改成times[2]数组中的值,如果想要达到题目中的要求,我们应该先对pathname进行stat操作,取出其中的结构,对想要进行改变的进行改变,不想改变的就不要动,再将所得的结果放到times[2]数组当中,就解决了问题。这个问题主要考察我们对utimes函数的理解。

apue4.14:

这里finger函数应该使用stat函数对文件中的atime,mtime进行读取然后进行相应的操作,最后得出的结论,告诉我们软件设计中的方法。

apue4.15:

这个cpio和tar命令使用过,这个问题暂时放一放吧。

——————————————————————————————————————————分割线2016.6.30

apue4.16:

这道题目就是让我们编一个小程序测试一下电脑上如果当前路径名超过了PATH_MAX后是否还能getcwd之类的命令,在我的电脑上还是可以的,下面先上代码吧,啊哈哈.

#include "apue.h"#include <limits.h>#include <string.h>int main () {    char name[] = "ithinkicandosomethingthatissodifferent";    char buf[2*PATH_MAX];    int length = 0;        if (chdir ("/tmp") < 0)         err_sys ("chdir error");    umask (0);    while (length <= PATH_MAX) {        if (mkdir (name , S_IRUSR | S_IWUSR | S_IXUSR) < 0)            err_sys ("mkdir error");        if (chdir (name) < 0)            err_sys ("chdir error");        length += strlen (name);    }    if (getcwd (buf , 2*PATH_MAX) == NULL)        err_sys ("getcwd error");    printf ("the length is %d\n" , length);    printf ("the PATH_MAX is %d\n" , PATH_MAX);    printf ("the size of buf is %d\n" , (int) strlen (buf));}
很简单的一个例程,但是还是有值得注意的地方,要对文件夹的权限提高意识,如果是root用户当然你爱怎么玩怎么玩,但是如果不是root用户,就要在当前文件夹创建文件夹之后,要设置执行权限,以便进入该目录,当然我觉得读和写权限也是有必要的,度可以显示文件夹中的内容而写权限则可以在文件夹中创建文件或者目录,还有就是在在当前工作目录,可以创建文件的时候使用相对文件路径。最后的结果在我的机器上,PATH_MAX是4096,length是4100多,而strlen(buf)比length大上了100多,原因是我在计算文件长度的时候没有计算'/'字符的长度。

apue4.17:

我对/dev/fd/#的理解不是那么深刻,我认为如果在文件中打开这个文件,相当等于打开了对应的文件描述符,如果是普通的用户执行这个程序的时候,书上的答案说是会拒绝unlink的,因为/dev/fd的目录设置当中将用户的写权限取消,所以无法改变文件夹中的内容。如果是超级用户那?啊哈哈,我去做个试验再来跟新吧。

————————————————————————————————————————————————————————分割线2016.7.3

第四章的内容就差不多跟新完啦,哈哈!



0 0