您的位置:首页 > 运维架构 > Linux

linux命令之——mv.c 文件解读 (coreutils-8.9)

2011-02-11 15:44 357 查看
本来今天是想吧unp那个实例搞定的,中途学了会Makefile 糊里糊涂的就研究了一下mv.c文件。

相信像上篇文章中使用mv命令的你早已很是熟悉这个命令了,咱们看看他的具体实现吧,本来是想直接在系统中找到他的,后来发现他却是个比Linux还要早的历史产物归属于GUN,直接到ftp://ftp.gnu.org/gnu/这里有个叫coreutils的文件夹就是啦,里面是我们用的各种命令,我下载的

是8.5写着个东西时候最新的版本了!

废话不多说,咱赶紧看看mv.c都干了什么吧!

/* 移动SOURCE到DEST.主要处理跨文件系统的情况如果SOURCE是一个目录, DEST必须不存在.
如果成功了返回true.  */
static bool
do_move (const char *source, const char *dest, const struct cp_options *x)
{
bool copy_into_self;
bool rename_succeeded;
bool ok = copy (source, dest, false, x, ©_into_self, &rename_succeeded);
if (ok)
{
char const *dir_to_remove;
if (copy_into_self)
{
/* 通常当SOURCE和DEST一样或者是DEST的父目录的时候copy会返回copy_into_self在这种情况
下我们知道SOURCE是作为一个父目录出现的,移动一个目录到他自己里是没有意义的 and 除此之
外在某些情况下这么做会带来很不直观的结果,在一个空目录中执行 `mkdir b; touch a c;
mv * b'.这时候会返回错误,mv: 无法将目录 “b” 移动至自身的子目录 “b/b” 下。通过一个
特征值处理这个问题, 删除copied-into-self目录, DEST (`b/b' 在这个例子中),并返回失
败.  */
dir_to_remove = NULL;
ok = false;
}
else if (rename_succeeded)
{
/* SOURCE成功的rename到DEST不许要删除任何文件,或者权限拒绝重命名一个文件 */
dir_to_remove = NULL;
}
else
{
/* 这个可能意味着SOURCE和DEST在不同的设备中也可能被认为是尽管SOURCE和DEST在同一个设
备中但是rename是不被允许的.
就好象你用ftpfs向ftp服务器申请上传,下载,删除但是不能重命名一样
在检查can-rename的时候设备号是不可靠的,因为有些系统从不同物理设备上建立文件但是他
们有相同的st_dev字段(NFS就是这样的)
如果SOURCE成功的copy到DECT,那么我们必须删除SOURCE
这个函数通常用在复制只是当重命名失败并且设置errno等于EXDEV  */
dir_to_remove = source;
}
if (dir_to_remove != NULL)
{
struct rm_options rm_options;
enum RM_status status;
char const *dir[2];
rm_option_init (&rm_options);
rm_options.verbose = x->verbose;
dir[0] = dir_to_remove;
dir[1] = NULL;
status = rm ((void*) dir, &rm_options);
assert (VALID_STATUS (status));
if (status == RM_ERROR)
ok = false;
}
}
return ok;
}
/* 移动文件SOURCE到DEST.主要处理DEST是目录的时候如果DEST_IS_DIR则DEST是目录
如果成功返回true.  */
static bool
movefile (char *source, char *dest, bool dest_is_dir,
const struct cp_options *x)
{
bool ok;
/*
这段代码处理由于重命名函数的不同语义导致的mv语义上的歧义
有些系统(如:GNU/Linux)的重命名函数处理最后的‘/’,
一些别的系统(如: Solaris 5,6,7)的重命名函数忽略最后的‘/’
(此处引用源代码中的注释)
*/
if (remove_trailing_slashes)
/*	bool strip_trailing_slashes(char *file)
函数删除FILE最后的‘/’ */
strip_trailing_slashes (source);
/* 如果第二个参数是目录 */
if (dest_is_dir)
{
/* 获取source整个路径名的最后部分 */
char const *src_basename = last_component (source);
/* 将获取的最后部分和dest连接构成新的目标路径 */
char *new_dest = file_name_concat (dest, src_basename, NULL);
strip_trailing_slashes (new_dest);
ok = do_move (source, new_dest, x);
/* 释放申请的内存 */
free (new_dest);
}
/* 如果第二个参数不是目录 */
else
{
ok = do_move (source, dest, x);
}
return ok;
}


上面的代码我翻译了mv.c的部分注释也加了一些我自己的注释

int
main (int argc, char **argv)
{
...
if (target_directory)
{
int i;
/* Initialize the hash table only if we'll need it.
The problem it is used to detect can arise only if there are
two or more files to move.  */
if (2 <= n_files)
dest_info_init (&x);
ok = true;
for (i = 0; i < n_files; ++i)
ok &= movefile (file[i], target_directory, true, &x);
}
else
ok = movefile (file[0], file[1], false, &x);
...
}


这段是main函数对上面两个主要函数的调用,其他的地方先略着,有兴趣的自己看看吧~~~

可以看出movefile函数主要是处理了目录的情况,和路径的问题,然后把实际的工作交给了do_move,然后do_move函数主要完成了当出现跨文件系统的时候怎么处理文件copy的后续工作,mv命令主要还是使用了copy.c中的copy函数,这个文件暂时我还没看全,先写这些防备忘记也分享给大家共同进步。

我这个英语很不给力,大家别见笑,想看原版的直接下载就好……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: