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

程序清单 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



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值