本文共 2195 字,大约阅读时间需要 7 分钟。
前言:
这是水煮coreutils 系列的第一篇,写下在读linux coreutils 代码的心得体会,随着难度的渐渐加大,不知道能把这个系列坚持到什么
时候,也许这是第一篇也就是最后一篇.
coreutils 是linux系统中最接近我们日常使用的部分,rm cp ls cat 等命令皆发于此,最常用意味着最稳定,最高效,偶自认为
目前不是看内核代码的那块料,那就从最基本的地方看起.
rm [ -f ] [ -r ] [ -R ] [ -i ] [ -e ] File
其中 i 是问不问要删除,r和R 表达一个意思要递归删除,e是显示删除的内容,f 不是我们想像的强制删除只是有错误信息不做提示
罢了.
通过 getopt_long 获取参数,参数放在struct rm_options中,不包括文件名.
那文件名是怎么获取的呢? 一个小技巧,以后在很多的应用程序中都会用到.
size_t n_files = argc - optind;
char const *const *file = (char const *const *) argv + optind;
获取到文件名以后,要做的事情就是删除了
enum RM_status status = rm (n_files, file, &x);
现在我们来看rm函数的实现:
在分析函数之前我们思考一下如果我们来实现这个函数,应当怎么做?
删除文件用remove 或者 unlink 函数,删除目录用rmdir函数,那么我们要做的事情就是遇到文件删除文件,遇到目录进入目录删除
文件,文件删除光光再出来删除目录,遇到删除不掉的就跳到上一级目录连着文件一起不删除.
rm的实现其实也很简单,拿
for (i = 0 ; i < n_files; i ++ ) ... { enum RM_status s; cycle_check_init (&ds->cycle_check_state); /**//* In the event that rm_1->remove_dir->remove_cwd_entries detects a directory cycle, arrange to fail, give up on this FILE, but continue on with any other arguments. */ if (setjmp (ds->current_arg_jumpbuf)) s = RM_ERROR; else s = rm_1 (ds, file[i], x, &cwd_state); assert (VALID_STATUS (s)); UPDATE_STATUS (status, s); } 注意一下这一句:setjmp (ds->current_arg_jumpbuf)
在以后的过程中会有意想不到的效果.
自顶向下 抽丝剥茧 偶们来到了 rm_1函数:
它做的事情很简单 跳过 . .. 文件,remove_entry 删除文件,如果返回值为非空目录,那就删除目录remove_dir.
判断文件是个有用的宏,记录一下
#define DOT_OR_DOTDOT(Basename) /
(Basename[0] == '.' && (Basename[1] == '/0' /
|| (Basename[1] == '.' && Basename[2] == '/0')))
现在来看remove_entry:
调用prompt,这个函数做多个事情,
第一 迎合-i选项问你是否要删除
第二 判断是否为目录,
第三 目录是否为空
返回值表达,如果为文件,链接,空目录等标志为可删除,如果为非空目录标志为非空目录,如果其它情况作为err返回.
接下来对于可删除的的东西就开始删除了.
来看remove_dir函数.
这个函数采取的方法是用几个堆栈保持目录,文件状态,然后调用remove_cwd_entries 删除本目录的内容.
那么来看remove_cwd_entries 函数
从函数名来说就是把当前目录下的所有文件删除,很多人会认为这个是递归实现的,其实这个才是rm这个程序的精华部分,
通过两个循环化解递归:
这个是伪代码表示,表示个流程,还有复杂的堆栈操作,递归是函数的压栈,这里是把目录名压栈,一定程度上保留了系统资源.
removedir() ... { while(1) ...{ remove_cwd_entries(dir); } } remove_cwd_entries() ... { while(1) ...{ if(isfile) rm(file) ; if(isdir) ...{ chdir(dir) break ; } } } 细看代码我们可以学到很多有用的东西,很多很精巧的宏和函数,比如判断一个数是否2的n次方
static inline bool is_power_of_two (unsigned int i) ... { return (i & (i - 1)) == 0;} 这种用法也很好
memcpy(mempcpy(str,buf1,strlen(buf1)),buf2,strlen(buf2) + 1 ) ; 转载地址:http://iskmi.baihongyu.com/