为什么看?

想要在删除文件前,先覆盖文件内容,防止他人恢复文件,从而得到文件原内容;并且需要支持rm命令原本的参数选项:

NAME
rm - remove files or directories
SYNOPSIS
rm [OPTION]... FILE...
Remove (unlink) the FILE(s).
-f, --force
ignore nonexistent files, never prompt
-i prompt before every removal
-I prompt once before removing more than three files, or when removing recursively. Less intru-
sive than -i, while still giving protection against most mistakes
......

想来还是直接修改rm源文件比较方便,因而查看rm命令的源码文件,在调用删除系统调用前加入覆盖文件内容的操作,从而安全删除文件,并且支持rm命令的参数选项。

怎么获取linux命令源码

可以通过三条命令获得命令的源代码网址

  • which rm //得到文件的绝对路径
  • rpm -qf 路径 //获取该命令所属的软件包名
  • rpm -qi 包名 //获取包信息,包含网址URL信息

如下:

[ty@ty ~]$ which rm
/bin/rm
[ty@ty ~]$ rpm -qf /bin/rm
coreutils-8.4-19.el6.x86_64
[ty@ty ~]$ rpm -qi coreutils
Name : coreutils Relocations: (not relocatable)
Version : 8.4 Vendor: Red Hat, Inc.
Release : 19.el6 Build Date: Tue 17 Apr 2012 06:14:13 AM PDT
Install Date: Sun 04 Aug 2013 11:48:59 AM PDT Build Host: hs20-bc2-3.build.redhat.com
Group : System Environment/Base Source RPM: coreutils-8.4-19.el6.src.rpm
Size : 12847030 License: GPLv3+
Signature : RSA/8, Thu 19 Apr 2012 10:59:38 PM PDT, Key ID 199e2f91fd431d51
Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
URL : http://www.gnu.org/software/coreutils/
Summary : A set of basic GNU tools commonly used in shell scripts
Description :
These are the GNU core utilities. This package is the combination of
the old GNU fileutils, sh-utils, and textutils packages.

rm.c主函数main

rm命令函数调用流程: 
man() -> rm() -> rm_fts() -> excise() -> unlinkat()

int main (int argc, char **argv)
{
bool preserve_root = true;
struct rm_options x;
bool prompt_once = false;
int c;
 
initialize_main (&argc, &argv); //初始化输入参数
set_program_name (argv[0]); //设置程序名
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
 
/* 程序正常结束前调用的close_stdin函数,关闭标准输入;
* 一个程序最多可以用atexit()注册32个处理函数,这些处理函数的
* 调用顺序与其注册顺序相反。即就是先注册的最后调用,最后调用的最先调用*/
atexit (close_stdin);
 
rm_option_init (&x); //初始化rm选项,即就是rm命令的参数
 
/* Try to disable the ability to unlink a directory. */
priv_set_remove_linkdir (); /*试图去禁用删除目录的功能,Try to remove priv from the effective set*/
 
while ((c = getopt_long (argc, argv, "dfirvIR", long_opts, NULL)) != -1)
{
switch (c) //switch语句主要是根据输入参数选项设置删除选项
{
case 'f':
x.interactive = RMI_NEVER;
x.ignore_missing_files = true;
prompt_once = false;
break;
 
case 'i':
x.interactive = RMI_ALWAYS;
x.ignore_missing_files = false;
prompt_once = false;
break;
case 'r':
case 'R':
x.recursive = true;
break; 
......
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
diagnose_leading_hyphen (argc, argv);
usage (EXIT_FAILURE);
}
}
 
if (argc <= optind) /*参数小于等于optind,即就是没有输入要删除的filename*/
{
if (x.ignore_missing_files) /*指定了-f选项时,直接退出,否则输出信息提示用户为指定操作对象*/
exit (EXIT_SUCCESS);
else
{
error (0, 0, _("missing operand"));
usage (EXIT_FAILURE);
}
}
 
if (x.recursive && preserve_root)
{
static struct dev_ino dev_ino_buf;
x.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
if (x.root_dev_ino == NULL)
error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
quote ("/"));
}
 
size_t n_files = argc - optind; /*n_files存储命令行指定操作对象个数,即就是要删除文件个数(目录视为一个)*/
char **file = argv + optind; /*file存储操作对象的索引*/
 
if (prompt_once && (x.recursive || 3 < n_files))
{
fprintf (stderr,
(x.recursive
? _("%s: remove all arguments recursively? ")
: _("%s: remove all arguments? ")),
program_name);
if (!yesno ())
exit (EXIT_SUCCESS);
}
 
enum RM_status status = rm (file, &x); /*删除文件,返回删除状态*/
assert (VALID_STATUS (status));
exit (status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS);
}

rm()函数

/* Remove FILEs, honoring options specified via X.
Return RM_OK if successful. */
enum RM_status
rm (char *const *file, struct rm_options const *x)
{
enum RM_status rm_status = RM_OK;
 
if (*file)
{
int bit_flags = (FTS_CWDFD
| FTS_NOSTAT
| FTS_PHYSICAL);
 
if (x->one_file_system)
bit_flags |= FTS_XDEV;
 
FTS *fts = xfts_open (file, bit_flags, NULL); //创建并填充FTS结构体部分成员信息,会调用fts_open函数,失败返回失败的诊断信息
 
while (1)
{
FTSENT *ent;
 
ent = fts_read (fts); //填充FTSENT结构体成员信息
if (ent == NULL)
{
if (errno != 0)
{
error (0, errno, _("fts_read failed"));
rm_status = RM_ERROR;
}
break;
}
 
enum RM_status s = rm_fts (fts, ent, x);
 
assert (VALID_STATUS (s));
UPDATE_STATUS (rm_status, s);
}
 
if (fts_close (fts) != 0)
{
error (0, errno, _("fts_close failed"));
rm_status = RM_ERROR;
}
}
 
return rm_status;
}

rn_fts()函数根据FTSENT结构体成员信息,做一些处理,然后调用excise()函数执行删除操作;

excise函数调用unlinkat系统函数

 
/* Remove the file system object specified by ENT. IS_DIR specifies
whether it is expected to be a directory or non-directory.
Return RM_OK upon success, else RM_ERROR. */
static enum RM_status
excise (FTS *fts, FTSENT *ent, struct rm_options const *x, bool is_dir)
{
int flag = is_dir ? AT_REMOVEDIR : 0;
if (unlinkat (fts->fts_cwd_fd, ent->fts_accpath, flag) == 0)
{
/* 使用了-v选项时,输出详细删除信息,是目录输出目录名,是文件输出文件名,
输出的是当前目录到删除文件的完全路径(" `/tmp/aa' "或者"`test/bb'") */
if (x->verbose)
{
printf ((is_dir
? _("removed directory: %s\n")
: _("removed %s\n")), quote (ent->fts_path)); /*quote是将输出用(`')反引号单引号括起来*/
}
return RM_OK;
}
 
//下边为unlinkat函数执行失败,做的一些处理
/* The unlinkat from kernels like linux-2.6.32 reports EROFS even for
nonexistent files. When the file is indeed missing, map that to ENOENT,
so that rm -f ignores it, as required. Even without -f, this is useful
because it makes rm print the more precise diagnostic. */
if (errno == EROFS)
{
struct stat st;
if ( ! (lstatat (fts->fts_cwd_fd, ent->fts_accpath, &st)
&& errno == ENOENT))
errno = EROFS;
}
 
if (ignorable_missing (x, errno))
return RM_OK;
 
/* When failing to rmdir an unreadable directory, the typical
errno value is EISDIR, but that is not as useful to the user
as the errno value from the failed open (probably EPERM).
Use the earlier, more descriptive errno value. */
if (ent->fts_info == FTS_DNR)
errno = ent->fts_errno;
error (0, errno, _("cannot remove %s"), quote (ent->fts_path));
mark_ancestor_dirs (ent);
return RM_ERROR;
}
添加的覆盖文件内容的操作就是添加在unlinkat函数前边,因为上几步已经做好了rm命令选项的操作,使用不同参数的不同操作,unlinkat函数是最终执行删除操作的:
int flag = is_dir ? AT_REMOVEDIR : 0;
if(flag == 0) //根据flag标志判断是文件还是目录,如果是文件才执行覆盖操作,否则不做任何操作
{
//覆盖操作
}
if (unlinkat (fts->fts_cwd_fd, ent->fts_accpath, flag) == 0)

rm删除命令源码分析相关推荐

  1. docker stats命令源码分析结果

    2019独角兽企业重金招聘Python工程师标准>>> 本文是基于docker 1.10.3版本的源码,对docker stats命令进行源码分析,看看docker stats命令输 ...

  2. LinkedList中查询(contains)和删除(remove)源码分析

    一.contains源码分析 本文分析双向链表LinkedList的查询操作源码实现.jdk中源程序中,LinkedList的查询操作,通过contains(Object o)函数实现.具体见下面两部 ...

  3. 进程句柄表初始化,扩展,插入删除句柄源码分析

    一.为什么要有句柄 句柄是一个8字节的结构体,用途是指向内核对象.3环程序无法通过地址直接访问内核对象,所以需要用句柄来间接访问. 本文重点介绍句柄表,句柄本身则留到下一篇博客介绍.但因为接下来介绍句 ...

  4. rocketmq 消息删除_RocketMQ源码分析之文件过期删除机制

    1.由于RocketMQ操作CommitLog.ConsumeQueue文件,都是基于内存映射方法并在启动的时候,会加载commitlog.ConsumeQueue目录下的所有文件,为了避免内存与磁盘 ...

  5. spice-gtk的spicy命令源码分析

    1.主函数入口 int main(int argc, char *argv[]) {GError *error = NULL;GOptionContext *context;spice_connect ...

  6. Quartz的Scheduler初始化源码分析

    2019独角兽企业重金招聘Python工程师标准>>> Quartz的使用:http://donald-draper.iteye.com/blog/2321886  Quartz的S ...

  7. 阿里开源一站式分布式事务框架seata源码分析(AT模式下TM与RM分析)

    序言: 对于阿里开源分布式事务框架seata的详细了解可以参考官网,这里不会详细介绍.本章只会介绍seata中AT模式的源码分析(对阿seata有一定了解或者成功完成过demo). seata中一个事 ...

  8. Django源码分析10:makemigrations命令概述

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-makemigrations命令概述 Django项目中的数据库管理命令就是通过makemig ...

  9. Django源码分析8:单元测试test命令浅析

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-test命令分析 Django项目中提供了,test命令行命令来执行django的单元测试,该 ...

最新文章

  1. HDU 3046Pleasant sheep and big big wolf(切最小网络流)
  2. VS2013 越来越慢
  3. (树)判断二叉树是否为BST
  4. 小菜鸟学 Spring-Dependency injection(二)
  5. python报错 TypeError: an integer is required
  6. 如何取消 DiscuzX 帖子被系统自动隐?
  7. python3解释器执行'abcdd'.endswith('cd')的结果是___python3解释器执行for x
  8. js 根据掩码位计算可用ip地址_变长子网掩码:轻松分配IP地址(下)
  9. 《who Who Are You Working For》(你在为谁工作)
  10. Leetcode475.Heaters供暖器
  11. 网络安全实验室 脚本关 解析
  12. 如何彻底删除小黑记事本弹窗
  13. 常微分方程-差分方程
  14. U盘“请将磁盘插入U盘”,主控显示“chipYC2019”处理
  15. Java核心技术卷一(百度云资源)
  16. 中资电信银行股将成市场旗手
  17. 教你玩 Robocode(2) —— 使用Eclipse开发Robot
  18. php查询google pr值接口api介绍,php获取网站谷歌pr值方法
  19. java序列化机制Serialize接口使用
  20. Landscape-版图几何设计规则DRC

热门文章

  1. 股票做空是什么意思?股票做空和做多是什么意思?
  2. 怎么_如何制作h5页面?
  3. window7_64安装STAF
  4. Android多窗口分屏(原生方法)
  5. 计算hashCode通用计算公式
  6. RadioButtonList功能汇总
  7. 字体信息 TEXTMETRIC 字体结构 GLYPHMETRICS
  8. js输出sb (!(~+[]) + {})[--[~+][+[]] * [~+[]] + ~~!+[]] + ({} + [])[[~!+[]] * ~+[]] 图解
  9. 【光线追踪系列十七】直接光源采样
  10. calc() 工作原理