renameシステムコールとmvコマンド


Rev.4を表示中。最新版はこちら

システムコールにrenameというのがあり、それにもとづくrenameコマンドがありますが、通常ファイル名を変更する場合、mvコマンドを使つかいます。renameコマンドが直感的なコマンド体系でないからです。
[root@localhost a1]# man rename
書式
      rename from to file...
説明
      rename  は、指定したファイル名において from に最初にマッチする部分を to で置き換える。
たとえばaaaのファイルをbbbに置き換える場合、以下のように使うことになります。
[root@localhost a1]# ls
aaa
[root@localhost a1]# rename aaa bbb aaa
[root@localhost a1]# ls
bbb
mvコマンドだと
[root@localhost a1]# ls
bbb
[root@localhost a1]# mv bbb aaa
[root@localhost a1]# ls
aaa
renameコマンドは、ディレクトリの名前を変更することのみで実現しています。従って変更前のファイルと変更後のファイル名が同じファイルシステム下のファイルでないといけない制約があるからです。もし異なるファイルシステム下でも可能とするなら、ディレクトリの変更だけでなく、データブロックの移動の処理が発生することが考えられます。そうなるとvfs下でのrename処理が必要となります。vfsではrenameは定義されていません。
renameシステムコールが呼ばれると、sys_renameat(renameat)がコールされ、最初にファイルシステムが同じがどうかチェックしています。そしてファイルが書き込み可能とかの他のチェックをして、vfs_renameをコールします。
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
               int, newdfd, const char __user *, newname)
{
・・・・
       error = user_path_parent(olddfd, oldname, &oldnd, &from);
       if (error)
               goto exit;

       error = user_path_parent(newdfd, newname, &newnd, &to);
       if (error)
               goto exit1;

       error = -EXDEV;
       if (oldnd.path.mnt != newnd.path.mnt) <- ファイルシステムが違うとエラー
               goto exit2;
・・・・
       error = vfs_rename(old_dir->d_inode, old_dentry,
                                  new_dir->d_inode, new_dentry);
・・・・

vfs_renameではファイル名の変更か、ディレクトリ名の変更かで処理がわかれます。前者は vfs_rename_otherを後者はvfs_rename_dirがコールされ、そこからファイルシステムに依存したrenameコールバック関数へとわたります。そこから ディレクトリへの変更はext3_add_entryを経由して、 add_dirent_to_bufで書き込み内容を編集しそれをディレクトリにアペンドしています。その時、変更前のファイルのiノードをそのまま使用しています。
static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
                           struct inode *new_dir, struct dentry *new_dentry)
{
・・・・        if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
               error = -EBUSY;
       else
               error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
       if (!error) {
               if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
                       d_move(old_dentry, new_dentry);
       }
・・・・

static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
                            struct inode *inode, struct ext3_dir_entry_2 *de,
                            struct buffer_head * bh)
{
・・・・
        de->file_type = EXT3_FT_UNKNOWN;
       if (inode) {
               de->inode = cpu_to_le32(inode->i_ino); <- 変更前のiノード番号で上書き
               ext3_set_de_type(dir->i_sb, de, inode->i_mode);
       } else
               de->inode = 0;
       de->name_len = namelen;
       memcpy (de->name, name, namelen);
       dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
       ext3_update_dx_flag(dir);
       dir->i_version++;
・・・・
mvというシステムコールは無いようです。変更前のファイルを変更後のファイルとして複写し、変更前のファイルを削除すればよさそうです。そして、このコマンドはファイルシステムを超えて可能です。結果としては想像できそうなものですが、同じファイルシステム下でおこなうmvと、異なるファイルシステム下でおこなうmvを調べてみると、(straceでもいいのでしょうが・・・)
ファイルシステムが同じ
[root@localhost a1]# ls -i
103382 aaa
[root@localhost a1]# mv aaa ../a2/bbb
[root@localhost a1]# ls -i ../a2
103382 bbb
ファイルシステムが違う
[root@localhost a1]# ls -i
103388 aaa
[root@localhost a1]# mv aaa /mnt
[root@localhost a1]# ls -i /mnt/aaa
15 /mnt/aaa
同じファイルシステムではiノードが同じで、異なるファイルシステムでは、iノードが異なっています。mvコマンドで変更前と変更後のファイルが同じファイルシステムの場合、renameシステムコールを使っていることが推測できます。


最終更新 2010/01/26 21:24:09 - north
(2010/01/26 21:21:16 作成)


検索

アクセス数
3585769
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。