linux源码rm函数,linux的rm命令源码
Linux下的rm命令是个删除⽂件命令那么它的源代码是怎样的呢?下⾯由店铺为⼤家整理了linux下rm命令源码的相关知识,希望对⼤家有帮助!
linux的rm命令源码分析
1.原因
想要在删除⽂件前,先覆盖⽂件内容,防⽌他⼈恢复⽂件,从⽽得到⽂件原内容;并且需要⽀持rm命令原本的参数选项:
NAME rm - remove files or directoriesSYNOPSIS rm [OPTION]... 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命令的参数选项。
2.获取linux命令源码
可以通过三条命令获得命令的源代码⽹址
which rm //得到⽂件的绝对路径
rpm -qf 路径 //获取该命令所属的软件包名
rpm -qi 包名 //获取包信息,包含⽹址URL信息
如下:
linux的rm命令源码
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_statusrm (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_statusexcise (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
linux退出文件命令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)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论