unix高级环境编程 例子 代码实现练习 第四章:文件和目录

来源:互联网 发布:淘宝打折软件叫什么 编辑:程序博客网 时间:2024/05/01 23:39

程序清单 4-1 对每一个命令行参数打印文件类型

/** * 程序清单 4-1 对每一个命令行参数打印文件类型 * * zy: * 这就是说我们给一个指定的文件,请利用api判断出这个文件是什么类型 * 主要是利用了定义了在<sys/stat.h>的宏,P72有详细的解释 * 我们可以判断出是普通文件、字符特殊文件等等 * * */#include "apue.h"#include "error.c"int main(int argc, char **argv) {int i;struct stat buf;char *ptr;for(i = 1;i < argc; i++){printf("%s:",argv[i]);if(lstat(argv[i],&buf)<0){err_ret("lstat error");continue;}if(S_ISREG(buf.st_mode)){ptr="regular";}else if(S_ISDIR(buf.st_mode)){ptr="directory";}else if(S_ISDIR(buf.st_mode)){ptr="directory";}else if(S_ISCHR(buf.st_mode)){ptr="character special";}else if(S_ISBLK(buf.st_mode)){ptr="block special";}else if(S_ISFIFO(buf.st_mode)){ptr="FIFO";}else if(S_ISLNK(buf.st_mode)){ptr="symbolic link";}else if(S_ISSOCK(buf.st_mode)){ptr="socket";}else {ptr="** unknown mode **";}printf("%s \n",ptr);}exit(0);}

结果:

asd@asd-desktop:~/workspace/test/src$ ./a.out / ./test.c /dev/log /dev/tty \> /dev/cdrcdrom  cdrw   > /dev/cdrom/:directory ./test.c:regular /dev/log:socket /dev/tty:character special /dev/cdrom:symbolic link asd@asd-desktop:~/workspace/test/src$ 

程序清单 4-2 access函数实例 P78

/** * 程序清单 4-2 access函数实例 P78 * * zy: * access函数的关键就是一句话: * 验证实际用户有无权限读、写、执行等一个文件 * * 这是因为一个进程的实际用户是可以改变的, * 假如我们把一个进程的有效id改为了root,那么就以root的身份在执行 * 那么我们想知道实际用户到底有无权限接近一个文件呢?我们就需要使用access函数 * P75理论上说了怎么改以及实际用户、有效用户、设置用户的关系 * p78有一个实际改变有效用户的例子 *  */#include "apue.h"#include "error.c"#include "fcntl.h"int main(int argc, char **argv) {if(argc!=2){err_quit("usage:a.out <pathname>");}if(access(argv[1],R_OK)<0){err_ret("access error for %s ",argv[1]);}else {printf("read access ok\n");}if(open(argv[1],O_RDONLY)<0){err_ret("open error for %s",argv[1]);}else{printf("open for reading ok\n");}}
结果:

asd@asd-desktop:~/workspace/test/src$ ls -l a.out -rwxrwxr-x 1 asd asd 7837 Mar  8 08:55 a.outasd@asd-desktop:~/workspace/test/src$ ./a.out a.out read access okopen for reading okasd@asd-desktop:~/workspace/test/src$ ls -l /etc/shadow-rw-r----- 1 root shadow 1066 Oct  4 09:02 /etc/shadowasd@asd-desktop:~/workspace/test/src$ ./a.out /etc/shadowaccess error for /etc/shadow : Permission deniedopen error for /etc/shadow: Permission deniedasd@asd-desktop:~/workspace/test/src$ sudo chown root a.out [sudo] password for asd: asd@asd-desktop:~/workspace/test/src$ sudo chmod u+s a.out asd@asd-desktop:~/workspace/test/src$ ls -l a.out -rwsrwxr-x 1 root asd 7837 Mar  8 08:55 a.outasd@asd-desktop:~/workspace/test/src$ ./a.out /etc/shadowaccess error for /etc/shadow : Permission deniedopen for reading okasd@asd-desktop:~/workspace/test/src$ 

程序清单 4-3 umask函数实例 P79

/** * 程序清单 4-3 umask函数实例 P79 * * zy: * umask函数的关键就是一句话: * 它表示了当前限制的读写权限,无论open/creae怎么设置读写权限,都会被其限制 * */#include "apue.h"#include "error.c"#include "fcntl.h"#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)int main() {umask(0);//表示现在不限制任何读写权限if(creat("aaa",RWRWRW)<0){err_sys("create error for aaa");}umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);if(creat("bbb",RWRWRW)<0){err_sys("create error for bbb");}exit(0);}

结果:

asd@asd-desktop:~/workspace/test/src$ gcc test.c asd@asd-desktop:~/workspace/test/src$ ./a.out asd@asd-desktop:~/workspace/test/src$ ls -l aaa bbb-rw-rw-rw- 1 asd asd 0 Mar  8 09:17 aaa-rw------- 1 asd asd 0 Mar  8 09:17 bbbasd@asd-desktop:~/workspace/test/src$ ^C

程序清单 4-4 chmod函数实例 P82

/** * 程序清单 4-4 chmod函数实例 P82 * * zy: * chmod函数的关键就是一句话: * 改变当前文件的权限 * */#include "apue.h"#include "error.c"int main() {struct stat statbuf;if(stat("aaa",&statbuf)<0){err_sys("stat error for aaa");}if(chmod("aaa",(statbuf.st_mode & ~S_IXGRP)|S_ISGID)<0){//去掉组执行和打开执行时设置组IDerr_sys("chmod error for aaa");}if(chmod("bbb",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)<0){err_sys("chmod error for bbb");}exit(0);}


结果:

asd@asd-desktop:~/workspace/test/src$ ls -l aaa bbb-rw-rw-rw- 1 asd asd 0 Mar  8 09:17 aaa-rw------- 1 asd asd 0 Mar  8 09:17 bbbasd@asd-desktop:~/workspace/test/src$ gcc test.c asd@asd-desktop:~/workspace/test/src$ ./a.out asd@asd-desktop:~/workspace/test/src$ ls -l aaa bbb-rw-rwSrw- 1 asd asd 0 Mar  8 09:17 aaa-rw-r--r-- 1 asd asd 0 Mar  8 09:17 bbbasd@asd-desktop:~/workspace/test/src$ 

程序清单 4-5 打开一个文件,然后unlink它 P90

/** * 程序清单 4-5 打开一个文件,然后unlink它 P90 * * zy: * unlink就想当于删除它了,当时当程序没结束之前这个文件是不会被释放的 * 所以我们就相当于有了一种创建临时文件的方式,当进程结束之后这个文件就会被删除 * */#include "apue.h"#include "error.c"#include "fcntl.h"int main() {if(open("aaaa~",O_RDWR)<0){err_sys("open aaaa error");}if(unlink("aaaa~")<0){err_sys("unlink error");}printf("aaaa unlink");sleep(15);printf("done!");exit(0);}
结果:

asd@asd-desktop:~/workspace/test/src$ ls -l aaaa~-rw-rw-r-- 1 asd asd 92945879 Mar  8 09:53 aaaa~asd@asd-desktop:~/workspace/test/src$ df /homeFilesystem     1K-blocks    Used Available Use% Mounted on/dev/sda7        9483488 7725944   1275804  86% /asd@asd-desktop:~/workspace/test/src$ ./a.out &[1] 7364asd@asd-desktop:~/workspace/test/src$ df /homeFilesystem     1K-blocks    Used Available Use% Mounted on/dev/sda7        9483488 7725944   1275804  86% /[1]+  Done                    ./a.outasd@asd-desktop:~/workspace/test/src$ df /homeFilesystem     1K-blocks    Used Available Use% Mounted on/dev/sda7        9483488 7635172   1366576  85% /

程序清单 4-6 utime函数实例 P96

/** * 程序清单 4-6 utime函数实例 P96 * * zy: * 我们主要用这个函数来改变访问时间和修改时间 * 但是这个文件的修改状态的时间是我们无法控制的, * 然而当我们对其用utime函数设置访问时间和修改时间, * 文件的状态时间会根据实际情况来改变时间 * */#include "apue.h"#include "error.c"#include <utime.h>#include <fcntl.h>int main(int argc, char *argv[]){    int i,fd;    struct stat statbuf;    struct utimbuf timebuf;    for(i=1;i<argc;i++){        if(stat(argv[i],&statbuf)<0){        err_ret("%s:stat error",argv[i]);        }        if((fd=open(argv[i],O_RDWR|O_TRUNC))<0){        err_ret("%s:open error",argv[i]);        continue;        }        close(fd);        timebuf.actime=statbuf.st_atime;        timebuf.modtime=statbuf.st_mtime;        if(utime(argv[i],&timebuf)<0){        err_ret("%s:utime error",argv[i]);        continue;        }    }    exit(0);}

结果:

asd@asd-desktop:~/workspace/test/src$ ls -l aaa bbb-rw-rwSrw- 1 asd asd 0 Mar  8 09:17 aaa-rw-r--r-- 1 asd asd 0 Mar  8 09:17 bbbasd@asd-desktop:~/workspace/test/src$ ls -lu aaa bbb-rw-rwSrw- 1 asd asd 0 Mar  8 09:17 aaa-rw-r--r-- 1 asd asd 0 Mar  8 09:17 bbbasd@asd-desktop:~/workspace/test/src$ dateSat Mar  8 10:41:53 CST 2014asd@asd-desktop:~/workspace/test/src$ ./a.out aaa bbbasd@asd-desktop:~/workspace/test/src$ ls -l aaa bbb-rw-rwSrw- 1 asd asd 0 Mar  8 09:17 aaa-rw-r--r-- 1 asd asd 0 Mar  8 09:17 bbbasd@asd-desktop:~/workspace/test/src$ ls -lu aaa bbb-rw-rwSrw- 1 asd asd 0 Mar  8 09:17 aaa-rw-r--r-- 1 asd asd 0 Mar  8 09:17 bbbasd@asd-desktop:~/workspace/test/src$ ls -lc aaa bbb-rw-rwSrw- 1 asd asd 0 Mar  8 10:42 aaa-rw-r--r-- 1 asd asd 0 Mar  8 10:42 bbbasd@asd-desktop:~/workspace/test/src$ 

程序清单 4-7 递归降序遍历目录层次结构,并按文件类型计数 P105

/** * 程序清单 4-9 递归降序遍历目录层次结构,并按文件类型计数 P105 * * zy: * 直到我把代码全部写好我才明白这个例题想干什么。请看下面的结果 * */#include "apue.h"#include "error.c"#include <dirent.h>#include <limits.h>typedef int Myfunc(const char *,const struct stat *,int);//这是声明函数类型的一种方式。//理解为用Myfunc来代表参数为(const char *, const struct stat *, int)//并且返回值是int型的一类函数的总称static Myfunc myfunc;//这就相当于将上面那个Myfunc换了这句中的myfuncstatic int myftw(char *,Myfunc *);//第二个参数是函数的指针static int dopath(Myfunc *);static long nreg,ndir,nblk,nchr,nfifo,nslink,nsock,ntot;char* path_alloc(int* size){char *p = NULL;if(!size) return NULL;p = malloc(256);if(p)*size = 256;else*size = 0;return p;}int main(int argc, char *argv[]){int ret;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;}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 int myftw(char *pathname,Myfunc *func){int len;fullpath=path_alloc(&len);strncpy(fullpath,pathname,len);fullpath[len-1]=0;return(dopath(func));}static int dopath(Myfunc *func){struct stat statbuf;struct dirent *dirp;DIR *dp;int ret;char *ptr;if(lstat(fullpath,&statbuf)<0)//fullpath是随着程序输入的名字。return (func(fullpath,&statbuf,FTW_NS));if(S_ISDIR(statbuf.st_mode)==0)//失败返回0,成功返回非0return (func(fullpath,&statbuf,FTW_F));if((ret=func(fullpath,&statbuf,FTW_D))!=0){//走到这里表示是一个目录return ret;}ptr=fullpath+strlen(fullpath);//这个应该是完成让ptr指向fullpath的尾部*ptr++='/';//尾部添加/后再加1*ptr=0;//在/后面再加0if((dp=opendir(fullpath))==NULL)return(func(fullpath,&statbuf,FTW_DNR));while((dirp=readdir(dp))!=NULL){if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0){continue;}strcpy(ptr,dirp->d_name);//这里就已经将下一个目录添加到了fullpath的尾部了if((ret=dopath(func))!=0)//所以可以继续进行递归break;}ptr[-1]=0;if(closedir(dp)<0)err_ret("can't close directroy %s",fullpath);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);//如果是目录,那么type值应该为FTW_Dbreak;default:break;}break;case FTW_D:ndir++;break;case FTW_DNR:err_ret("can't read diretory %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);break;}return 0;}

结果,统计了该目录下有有多少文件,目录之类的:
asd@asd-desktop:~/workspace/test/src$ ./a.out /homeregular files =   11557,80.32 %directories   =    2608,18.12 %block special =       0, 0.00 %char special  =       0, 0.00 %FIFOs         =       0, 0.00 %symbolic links=     222, 1.54 %sockets       =       2, 0.01 %

程序清单 4-8 chdir实例 P103

/** * 程序清单 4-8 chdir实例 P103 * * zy: * 不会改变的原因是: * 当我们在shell里面执行这一段命令时, * 会是一个子进程来帮我们完成改变目录的命令, * 没有影响到运行shell的进程 * */#include "apue.h"#include "error.c"int main(int argc, char *argv[]){if(chdir("/tmp")<0)err_sys("chdir failed");printf("chdir to /tmp done!\n");exit(0);}

结果:

asd@asd-desktop:~/workspace/test/src$ pwd/home/asd/workspace/test/srcasd@asd-desktop:~/workspace/test/src$ ./a.outchdir to /tmp done!asd@asd-desktop:~/workspace/test/src$ pwd/home/asd/workspace/test/src

程序清单 4-9 getcwd函数实例 P103

/** * 程序清单 4-9 getcwd函数实例 P103 * * zy: * getcwd可以获得当前工作目录的完成的绝对路径名。 * 我们换了目录之后用其来打印目录名 * */#include "apue.h"#include "error.c"char* path_alloc(int* size){char *p = NULL;if(!size) return NULL;p = malloc(256);if(p)*size = 256;else*size = 0;return p;}int main(int argc, char *argv[]){char *ptr;int size;if(chdir("/tmp")<0)err_sys("chdir failed");ptr=path_alloc(&size);//作者写的函数,但是if(getcwd(ptr,size)==NULL){err_sys("getcwd failed");}printf("cwd= %s \n",ptr);exit(0);}

结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out cwd= /tmp asd@asd-desktop:~/workspace/test/src$ 

  • 关于path_alloc函数(APUE)

程序清单 4-10 打印st_dev和st_rdev P105


/** * 程序清单 4-10 打印st_dev和st_rdev P105 * * zy: * st_dev包含文件系统的主次设备号3 * st_rdev是包含实际的设备号 * * 但是无论如何都可以使用major和minor这个宏来打印其主次设备号 *  */#include "apue.h"#include "error.c"#include <sys/sysmacros.h>//我的ubuntu12.04版本,linux应该是2.6int main(int argc, char *argv[]){int i;struct stat buf;for(i = 1; i<argc; i++){printf("%s: ",argv[i]);if(stat(argv[i],&buf)<0){err_ret("stat error");continue;}printf("dev= %d/%d",major(buf.st_dev),major(buf.st_dev));if(S_ISCHR(buf.st_mode)|| S_ISBLK(buf.st_mode)){printf("(%s) rdev=%d/%d",(S_ISCHR(buf.st_mode))?"character":"block",major(buf.st_rdev),minor(buf.st_rdev));}printf("\n");}exit(0);}


结果:

asd@asd-desktop:~/workspace/test/src$ ./a.out / /home/asd /dev/tty[01]/: dev= 8/8/home/asd: dev= 8/8/dev/tty0: dev= 0/0(character) rdev=4/0/dev/tty1: dev= 0/0(character) rdev=4/1



0 0