Linux系统编程26 目录和用户操作 - 实现自己的du命令

ls 查看 非隐藏文件

ls -a 查看所有文件,包括隐藏的文件,以 . 开头的
. :当前目录

mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ ls
mydu.c
mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ 
mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ ls -a
.  ..  mydu.c
mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ 

不能 glob 当前目录 . 和上级目录 … 会导致栈破裂

.
实验: 实现自己的简单的 du 命令

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glob.h>
#include <string.h>

#define PATHSIZE 1024


static int path_noloop(const char *path)
{
	char *pos;
	
	//定位最右边的'/'的位置
	pos = strrchr(path,'/');
	if(pos == NULL)
	exit(1);

	//判断 当前文件是 "." 和 ".." ,这两种情况不操作 直接越过,不然会导致栈破裂
	if(strcmp(pos+1,".")==0 || (strcmp(pos+1,"..")==0))
		return 0;

	return 1;
}

//防止大小溢出 long long int
static int64_t mydu(const char *path)
{
	struct stat statres;
	char nextpath[PATHSIZE];
	glob_t globres;
	int i;
	int64_t sum=0;
    //不使用 stat 遇到链接文件的时候 会返回 实际链接文件的属性信息,而我们此时需要返回链接文件本身属性信息
	if(lstat(path,&statres) < 0)
	{
		perror("lstat");
		exit(1);
	}
	//如果是非目录文件,直接返回文件大小 k: 块数/2
	 if(!S_ISDIR(statres.st_mode))
		return statres.st_blocks;

	// nextpath/*
	//strcpy(nextpath,path);
	strncpy(nextpath,path,PATHSIZE);
	strncat(nextpath,"/*",PATHSIZE);
	
	glob(nextpath,0, NULL, &globres);

	// nextpath/.*
	//strcpy(nextpath,path);
	strncpy(nextpath,path,PATHSIZE);
	strncat(nextpath,"/.*",PATHSIZE);
	glob(nextpath,GLOB_APPEND,NULL,&globres);


	sum += statres.st_blocks;

	for(i =0; i < globres.gl_pathc; i++)
	{
		//排除 . 和 ..文件
		if(path_noloop(globres.gl_pathv[i]))
		sum += mydu(globres.gl_pathv[i]);
	}
	
   globfree(&globres);
	return sum;
}

int main(int argc,char* argv[])
{
	if(argc < 2)
	{
		fprintf(stderr,"Usage:%s <src_file> <dest_file>\n",argv[0]);
		exit(1);
	}

	printf("%lld\n",mydu(argv[1])/2);


	exit(0);
}




mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ gcc mydu.c 
mydu.c: In function ‘main’:
mydu.c:75:9: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘int64_t {aka long int}’ [-Wformat=]
  printf("%lld\n",mydu(argv[1])/2);
         ^
mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ ./a.out /etc/
13480
mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ du /etc/
...
13480	/etc/

异常:
int glob() 成功返回0,我在测试代码的时候 发现 如果我对 glob()的结果进行校验,发现不能正常计算出目标文件的大小,经测试 发现 glob()函数有返回3的情形:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glob.h>
#include <string.h>

#define PATHSIZE 1024


static int path_noloop(const char *path)
{
	char *pos;
	pos = strrchr(path,'/');
	if(pos == NULL)
	exit(1);

	if(strcmp(pos+1,".")==0 || (strcmp(pos+1,"..")==0))
		return 0;

	return 1;
}

static int64_t mydu(const char *path)
{
	struct stat statres;
	char nextpath[PATHSIZE];
	glob_t globres;
	int i,err=0;
	int64_t sum=0;

	if(lstat(path,&statres) < 0)
	{
		perror("lstat");
		exit(1);
	}

	 if(!S_ISDIR(statres.st_mode))
		return statres.st_blocks;

	// nextpath/*
	//strcpy(nextpath,path);
	strncpy(nextpath,path,PATHSIZE);
	strncat(nextpath,"/*",PATHSIZE);
	
	glob(nextpath,0, NULL, &globres);

	// nextpath/.*
	//strcpy(nextpath,path);
	strncpy(nextpath,path,PATHSIZE);
	strncat(nextpath,"/.*",PATHSIZE);
	err = glob(nextpath,GLOB_APPEND,NULL,&globres);
	printf("err = %d\n",err);

	if(err)
	{
		fprintf(stderr,"glob():%s\n",strerror(err));
		exit(1);
	}


	sum += statres.st_blocks;

	for(i =0; i < globres.gl_pathc; i++)
	{
		if(path_noloop(globres.gl_pathv[i]))
		sum += mydu(globres.gl_pathv[i]);
	}

	return sum;
}

int main(int argc,char* argv[])
{
	if(argc < 2)
	{
		fprintf(stderr,"Usage:%s <src_file> <dest_file>\n",argv[0]);
		exit(1);
	}

	printf("%lld\n",mydu(argv[1])/2);


	exit(0);
}


...
err = 0
err = 0
err = 0
err = 0
err = 0
err = 3
glob():No such process
mhr@ubuntu:~/work/linux/muluheyonghucaozuo/26$ 

所以暂时没有加 glob 的返回值判断。

后面补充用 目录流 实现du命令。

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/105981004
今日推荐