水煮coreutils之 rm

来源:互联网 发布:淘宝新店如何经营视频 编辑:程序博客网 时间:2024/04/30 16:59
 前言:
    这是水煮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) ; 

 
   
 
原创粉丝点击