程序清单 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/cdr
cdrom 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.out
asd@asd-desktop:~/workspace/test/src$ ./a.out a.out
read access ok
open for reading ok
asd@asd-desktop:~/workspace/test/src$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1066 Oct 4 09:02 /etc/shadow
asd@asd-desktop:~/workspace/test/src$ ./a.out /etc/shadow
access error for /etc/shadow : Permission denied
open error for /etc/shadow: Permission denied
asd@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.out
asd@asd-desktop:~/workspace/test/src$ ./a.out /etc/shadow
access error for /etc/shadow : Permission denied
open for reading ok
asd@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 bbb
asd@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){//去掉组执行和打开执行时设置组ID
err_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 bbb
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-rwSrw- 1 asd asd 0 Mar 8 09:17 aaa
-rw-r--r-- 1 asd asd 0 Mar 8 09:17 bbb
asd@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 /home
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda7 9483488 7725944 1275804 86% /
asd@asd-desktop:~/workspace/test/src$ ./a.out &
[1] 7364
asd@asd-desktop:~/workspace/test/src$ df /home
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda7 9483488 7725944 1275804 86% /
[1]+ Done ./a.out
asd@asd-desktop:~/workspace/test/src$ df /home
Filesystem 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 bbb
asd@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 bbb
asd@asd-desktop:~/workspace/test/src$ date
Sat Mar 8 10:41:53 CST 2014
asd@asd-desktop:~/workspace/test/src$ ./a.out aaa bbb
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 bbb
asd@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 bbb
asd@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 bbb
asd@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换了这句中的myfunc
static 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,成功返回非0
return (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;//在/后面再加0
if((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_D
break;
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 /home
regular 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/src
asd@asd-desktop:~/workspace/test/src$ ./a.out
chdir 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$
程序清单 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.6
int 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