前言:
这是水煮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
++
)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
enum RM_status s;
cycle_check_init (&ds->cycle_check_state);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* 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()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
while(1)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
remove_cwd_entries(dir);
}
}
remove_cwd_entries()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
while(1)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
if(isfile)
rm(file) ;
if(isdir)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
chdir(dir)
break ;
}
}
}
细看代码我们可以学到很多有用的东西,很多很精巧的宏和函数,比如判断一个数是否2的n次方
static
inline
bool
is_power_of_two (unsigned
int
i)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
return (i & (i - 1)) == 0;
}
这种用法也很好
memcpy(mempcpy(str,buf1,strlen(buf1)),buf2,strlen(buf2)
+
1
) ;
这是水煮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的实现其实也很简单,拿
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
注意一下这一句: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这个程序的精华部分,
通过两个循环化解递归:
这个是伪代码表示,表示个流程,还有复杂的堆栈操作,递归是函数的压栈,这里是把目录名压栈,一定程度上保留了系统资源.
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
细看代码我们可以学到很多有用的东西,很多很精巧的宏和函数,比如判断一个数是否2的n次方
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
这种用法也很好
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)