Vim はファイルの権限を破ることができますか?

Vim はファイルの権限を破ることができますか?

先日、いつものように Vim を使っていたところ、奇妙なことに気付きました。私がやったことは次のとおりです。

~$ touch testfile
~$ ls -l | grep testfile
-rw-r--r-- 1 username groupname 0 Jul 23 10:00 testfile
~$ vim testfile

その後、変更を加えて保存し、 で終了しました:wq。ごく普通です。しかし、その後、

~$ sudo chown root:root testfile
~$ sudo chmod 644 testfile
~$ sudo -k
~$ ls -l | grep testfile
-rw-r--r-- root root 0 Jul 23 10:02 testfile
~$ vim testfile

したがって、root は r/w アクセス権限を持ち、他のユーザーは読み取り権限のみを持つ必要があります。ファイルを編集して保存しようとすると、保存できません。すばらしい、意図したとおりに動作しています。ただし、 で保存すると:w!、vim は何らかの理由でファイルの所有権を username:usergroup に戻して、ファイルが保存されます。次のようにしても:

~$ sudo chmod 444 testfile
~$ sudo -k
~$ ls -l | grep testfile
-r--r--r-- 1 root root 0 Jul 23 10:06 testfile
~$ vim testfile

あなたはできるまだ!で上書きします:w!。何が起こっているのでしょうか? vim はどのようにしてこのようにファイルの所有権と権限の法則を破ることができるのでしょうか? vim のヘルプ ページを次のように確認したところ:help :w、次のことがわかりました。

:w[rite]! [++opt]    Like ":write", but forcefully write when 'readonly' is set or there is another reason why writing was refused.
                     Note: This may change the permission and ownership of the file and break (symbolic) links. Add the 'W' flage to 'cpoptions' to avoid this.

以前、vim でファイルに書き込むことができなかったのですが、これはできないはずでした。質問の本質は、vim でファイルを編集できないようにするにはどうしたらよいか、なぜ期待どおりにファイル システムの権限に基づいていないのか、そして vim は他のエディター (gedit、nano) では使用できないどのようなメカニズムを使用してファイルを編集しているのか、ということだと思います。

編集: 私がこれを試したコンピューターは Linux カーネル 3.15.5-2-ARCH を使用しています。Vim のバージョン番号は 7.4.373-1 で、これはpacman私がインストールしたものです。特別なオプションを使用して最初からコンパイルしたわけではありません。

答え1

~現在のパスは、ユーザーのホーム ディレクトリであることがわかります。そのディレクトリへの書き込み権限が必要です。

別の方法で考えてみましょう。ディレクトリへの読み取りおよび書き込み権限がある場合、ファイルをコピーし、古いファイルを削除して、異なる権限で新しいファイルの名前を変更することを妨げるものは何でしょうか?

まさにこれが vim が行うことです。


たとえば、strace で vim を実行する場合:

open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0644) = -1 EACCES (Permission denied)
lstat("testfile", {st_mode=S_IFREG|0644, st_size=10, ...}) = 0
getuid()                                = 1000
unlink("testfile")                      = 0
open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
write(3, "ffjidfjds\n", 10)             = 10
fsync(3)                                = 0
close(3)                                = 0
chmod("testfile", 0644)                 = 0

このログに基づいて、次のプロセスを推測できます。

簡潔にするために、以前の権限チェック (およびchown試行など) の一部は省略されています。

  1. open書き込み用にファイルを開こうとしました (失敗: 権限が拒否されました)
  2. lstatファイルの所有者を確認する
  3. getuuid現在のユーザーIDをチェックして、ファイルの所有者と一致するかどうかを確認します。
  4. unlinkファイルを削除します(ディレクトリへの書き込み権限があるため許可されます)
  5. open同じ名前で新しいファイルを作成する
  6. writeファイルの内容(先ほど読んだとおり、意味不明な内容を入力してしまいました)
  7. fsyncファイルをディスクにフラッシュする(それほど重要ではない)
  8. close
  9. chmod新しいファイルの権限を古いファイルと同じよう変更します。新しい所有者がいるだけです。

関連情報