为什么看?

想要在删除文件前,先覆盖文件内容,防止他人恢复文件,从而得到文件原内容;并且需要支持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. 用二项逻辑斯蒂回归解决二分类问题
  2. XCTF-Reverse:re1
  3. .Net(C#)用正则表达式清除HTML标签(包括script和style),保留纯本文(UEdit中编写的内容上传到数据库)...
  4. mybatis 二级缓存失效_二级缓存updateBatchById失效
  5. 在计算机网络中通常所说的wlan是指,在计算机网络中,通常所说的WLAN是指()。 - 问答库...
  6. (3)Matplotlib_subplot, subplots
  7. 杭电acm2030汉字统计
  8. 实验server2003的域环境里安装一台Server2008 DC
  9. python scikit learn 关闭开源_Python开源机器学习框架:Scikit-learn六大功能,安装和运行Scikit-learn...
  10. HTML5网页扫描二维码
  11. Matlab的复共轭转置
  12. html语言ppt,htmlppt课件
  13. ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
  14. dspbios设计指南_视频广告设计者指南
  15. linux人员最爱用的键盘,Linux工作者必备-filco 87 忍者2代 黑色青轴
  16. 什么是运维?运维工程师主要是做什么?
  17. java 检测u盘_java实现监听u盘示例分享
  18. 小型仓库管理系统MySQL
  19. PLC(Power Line Carrier)电力线载波介绍
  20. java全栈系列之JavaSE-稀释数组029

热门文章

  1. shiro自定义filter,anon不生效
  2. Google 人工智能基本原则
  3. 面试时应该如何进行自我介绍呢
  4. [RK3399][Android7.1] 问题记录 --- GPU 重启问题分析
  5. HTML标签的属性和特性
  6. Java自由虾旅行平台菜单功能
  7. Elasticsearch 6.4 ingest-attachment对office文件IK分词器全文检索(1) HttpAPI使用
  8. 执念斩长河暑期出发录
  9. 新版悟能口罩预约小程序源码V1.1.1
  10. 打造数智制造“新引擎”,用友U9 cloud助百得胜加速崛起