C++ 学习 ---cstdio 的源码学习分析 03- 文件重命名函数 rename
cstdio 中的文件操作函数
stdio.h 中定义了文件删除函数 remove,文件重命名函数 rename,打开临时文件函数 tmpfile,生成临时文件名函数 tmpnam。接下来我们一起来分析一下 rename 对应的源码实现。
文件重命名函数 rename
使用新的文件名替换旧的文件名
在 glibc/libio/stdio.h 中与 rename 相关的函数增加了两个 renameat(替换时增加了 FD 的关联),renameat2(替换时增加 FD 的关联,flags 信息,表示三种不同的模式:RENAME_NOREPLACE,RENAME_EXCHANGE,RENAME_WHITEOUT)
实现方式---unix 方式
代码参考:/glibc/sysdeps/unix/sysv/linux/rename.c
实际上就是通过调用 INLINE_SYSCALL_CALL 实现的
INLINE_SYSCALL_CALL 的实现,继续调用__INLINE_SYSCALL_DISP,注意这里实际上是将__INLINE_SYSCALL 和后面的数据做了连接操作("##"在宏中做字符串连接)
这里有必要分析一下__SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
中__INLINE_SYSCALL_NARGS(__VA_ARGS__)
的作用,
可以看到,它在传入参数的后面添加了 7-0 共 8 个参数传递给__INTERNAL_SYSCALL_NARGS_X,该宏按顺序筛选出第 9 个数 n,即如果__VA_ARGS__只有一个参数,n=0,两个参数 n=1,
所以INLINE_SYSCALL_CALL (rename, old, new)
三个参数,n=2,被宏展开为__INLINE_SYSCALL2(rename,old,new)
,再按照宏展开为INTERNAL_SYSCALL (rename, 2, old, new)
对应架构的实现如下:glibc/sysdeps/unix/sysv/linux/x86_64/sysdep.h
其中 number 为连接出的_NR_rename,这也说明了最开始判断#if defined (__NR_rename)
的原因,
arg1,arg2 分别为输入的 old,new,调用汇编进行执行。
renameat 和 renameat2 的调用与之类似,这里就不做过多说明了,需要注意的是 renameat 调用中使用的 flags 是 0(默认值)。
实现方式---mach 内核架构实现
glibc/sysdeps/mach/hurd/rename.c,实际上是调用__dir_rename 实现的,不做更深入解读了
实现方式---posix 实现
glibc/sysdeps/posix/rename.c
逻辑也比较好理解,使用__link 完成对应的 rename 操作,然后使用__unlink 断开 oldname,大部分代码是针对出现异常时,即返回值小于 0 的异常处理,如前一处条件中考虑到了 EEXIST(文件存在)的情况,那就需要删除新文件,重新尝试__link,删除 old 文件时也是,出现异常,同时也要将新文件删除,保证最后失败不会带来额外的影响。具体__link 和__unlink 的调用基本也都是基于 syscall 实现的,就不展开细说了。
版权声明: 本文为 InfoQ 作者【桑榆】的原创文章。
原文链接:【http://xie.infoq.cn/article/93db72c20e3c2040056550790】。文章转载请联系作者。
评论