自定义du命令-------mydu
最近在学Linux C编程,跟着教程简单的编写了一个类似于Linux系统中du命令的程序,用于显示指定的目录或文件所占用的磁盘空间,简单的记录一下与分享,写的不好还请不吝赐教
程序中用到库的部分函数原型:
lstat
NAME
stat, fstat, lstat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
strchr
NAME
strchr, strrchr, strchrnul - locate character in string
SYNOPSIS
#include <string.h>
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <string.h>
char *strchrnul(const char *s, int c);
DESCRIPTION
The strchr() function returns a pointer to the first occurrence of the character c in the string s.
The strrchr() function returns a pointer to the last occurrence of the character c in the string s.
mydu.c
#include<stdio.h>
#include<stdlib.h>
#include<glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#define PATHSIZE 1024
//path_noloop函数用于判断子文件是否为“.”或者“..”,避免陷入无限递归中
static int path_noloop(char *path)
{
char *pos;
//获得目标路径中最后一个“/”右边的字符串
pos = strrchr(path,'/');
//return NULL,if not found '/'
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;
int64_t sum;
if (lstat(path,&statres) < 0)
{
perror("lstat()");
exit(1);
}
//判断是不是目录,如果不是目录,则直接跳出函数,返回文件的blocks大小,否则继续往下执行
if(!S_ISDIR(statres.st_mode))
//indicates the number of blocks allocated to the file, 512-byte units
return statres.st_blocks;
//匹配目标路径下的非隐藏文件
strncpy(nextpath,path,PATHSIZE);
strncat(nextpath,"/*",PATHSIZE);
glob(nextpath,0,NULL,&globres);
//匹配目标路径下的隐藏文件,并把文件信息追加到glores结构体中
strncpy(nextpath,path,PATHSIZE);
strncat(nextpath,"/.*",PATHSIZE);
glob(nextpath,GLOB_APPEND,NULL,&globres);
//printf("globres:%d\n",globres.gl_pathc);
//include the first dir itself
//通过递归来计算目标路径下的子目录下的文件的大小
sum = statres.st_blocks;
for (i =0;i<globres.gl_pathc;i++)
{
//path_noloop函数用于判断子文件是否为“.”或者“..”,避免陷入无限递归中
if (path_noloop(globres.gl_pathv[i]))
sum += mydu(globres.gl_pathv[i]);
//printf("test");
}
//释放globres中申请的内存
globfree(&globres);
return sum;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stderr,"Need a pathname as arg\n");
exit(1);
}
//使用long long类型也是因为防止输出结果太大,超出整型的表示范围而导致出错
//输出的大小单位是KB,而一个blocks的大小是512B,所以每两个blocks代表1KB,所有最终大小除以2
printf("%lld\n",(mydu(argv[1])/2));
exit(0);
}
运行结果:
[root@rio mydu]# ./mydu /root/sys_pro/fs/mydu
20
[root@rio mydu]# du /root/sys_pro/fs/mydu
20 /root/sys_pro/fs/mydu
可以看到mydu得到的结果和du得到的目标文件的大小都是20KB