web-dev-qa-db-ja.com

vimはどのようにして読み取り専用モードを上書きしますか?

編集後、vimに保存しようとしているファイルが読み取り専用であると報告されることがよくあります。これを回避する方法は、!wqを追加することです。vimプログラムが読み取り専用ファイルを書き込むための十分な権限を取得できるようにするために、内部で何が行われるのかを理解しようとしていますか?

切り替えられる内部フラグはありますか、またはvimは一時的に一時的に特権を取得しますか?

24
Atul

Vimで_w!_を実行すると、実際に何が発生するかは、ファイルの所有者によって異なります。

  • あなた(現在のユーザー)がファイルの所有者である場合、Vimはファイルを書き換える前にアクセス許可を書き込み可能に変更します。次に、書き込み許可を削除して、許可ビットを最初から元に戻します。

  • ファイルの所有者ではないが、現在のディレクトリに書き込み権限がある場合、Vimは元のファイルを削除し、同じ名前の新しいファイルにドキュメントを書き込みます。新しいファイルには元のファイルと同じ権限が割り当てられますが、所有者はあなたです。

Vimがファイルに書き込むための昇格された特権を獲得することは決してありません。

上記のメカニズムは、読み取り専用ファイルに書き込む必要のあるプログラムから選択する必要がある使用可能なオプションです(つまり、ファイルへの書き込み中に一時的にアクセス許可を変更するか、ファイルを削除して新しいアクセス許可を作成します)。 Vimが最終的に何を選択するかは、最終的には構成可能な設定の数によって異なります。

以下のコメントに見られるように、上記についてはいくつかの混乱があります。特定のブランドのUnixでのVimのセットアップで実際に何が起こるかを自分で確認したい場合は、Vimが読み取り専用ファイルへの書き込み中に行うシステムコールをトレースすることをお勧めします。これがどのように行われるかは、使用しているUnixによって異なります。 Linuxでは、これはたとえば_strace vim file_(次にファイルを編集し、_w!_で保存して終了します)。


これは最初のケースです(OpenBSDのktrace + kdumpからの出力):

_13228 vim      CALL  chmod(0x19b1d94b4b10,0100644<S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH|S_IFREG>)
13228 vim      NAMI  "file"
13228 vim      RET   chmod 0
13228 vim      CALL  lseek(3,0x1000,SEEK_SET)
13228 vim      RET   lseek 4096/0x1000
13228 vim      CALL  write(3,0x19b1e0aa9000,0x1000)
_

これにより、ファイルへのアクセス許可が変更され、書き込み可能になり(chmod()で使用される_S_IWUSR_フラグ)、バッファがファイルに書き込まれます。

次に、元の権限を設定します。

_13228 vim      CALL  fchmod(4,0100444<S_IRUSR|S_IRGRP|S_IROTH|S_IFREG>)
13228 vim      RET   fchmod 0
13228 vim      CALL  close(4)
13228 vim      RET   close 0
_

その他の場合:

最初にファイルのリンクを解除(削除)してから、ファイルを再作成します(ファイルに書き込み、後で権限を変更する前に)。

_44487 vim      CALL  unlink(0x79fdbc1f000)
44487 vim      NAMI  "file"
44487 vim      RET   unlink 0
44487 vim      CALL  open(0x79fdbc1f000,0x201<O_WRONLY|O_CREAT>,0644<S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH>)
44487 vim      NAMI  "file"
44487 vim      RET   open 4
_
26
Kusalananda

Vimは追加の権限を取得できません。 :w!は、内部'readonly'オプションをオーバーライドするだけです。これは、次の理由で設定された可能性があります。

  • -Rコマンドラインオプションを使用して、または:viewの代わりに:editを使用してファイルを開いた、または:setlocal readonly
  • Vimは、ファイルに現在書き込み権限がないことを認識しています

後者の場合、Vim(デフォルト)が新しいファイルを作成し、元のファイルをそのファイルで置き換えるため、ファイルの書き込みがまだ可能です。これは、これを許可するように設定されている権限に依存します。


Vimを開いたユーザーが何も持っていない場合に実際に書き込み権限を取得するには、直接、または SudoEdit のようなプラグインを通じて:w !Sudo tee >/dev/null fileトリックを使用する必要があります。

4
Ingo Karkat

書き込み権限のないファイルに書き込むことはできません。ただし、ディレクトリへの書き込み権限がある場合は、そのファイルを削除できます。

VIM=が使用しているトリックは、ファイルを削除して新しいファイルを書き込むことです。

これがメソッドであることを示すことは可能ですVIMソースコードを読み取らずに inode番号 の前後をチェックすることで使用:

$ touch foo
$ chmod u-w foo
$ ls -li foo
60818465 -r--r----- 1 philip philip 0 Feb 25 10:24 foo
$ vi foo
$ # edit the file and save with :w!
$ ls -li foo
60818467 -r--r----- 1 philip philip 8 Feb 25 10:25 foo

Iノード番号が変更され、新しいファイルが編集したファイルと同じでないことを示していることに注意してください。


FYI私の現在の設定は本当に短いです:

runtime! debian.vim
if has("syntax")
  syntax on
endif
set tabstop=4
set autoindent

インストールされているdebianパッケージは次のとおりです。

vim                               2:8.1.0875-1
vim-common                        2:8.1.0875-1
vim-runtime                       2:8.1.0875-1
vim-tiny                          2:8.1.0875-1
2
Philip Couling

Vimがvi互換モードの場合、:w!は、バッファの読み取り専用モードをオーバーライドするだけですが、ファイルのアクセス許可を前後に変更したり、別のファイルの名前を元の名前に変更してアクセス許可をバイパスしたり、他のアマチュア時間のものを実行したりしません。

これが唯一の正しい動作です私見-これを制御するフラグはW/cpoptionsからのcpoです。 :help cpoから:

                                                *'cpoptions'* *'cpo'* *cpo*
'cpoptions' 'cpo'       string  (Vim default: "aABceFs",
                                 Vi default:  all flags)
...
                                                                *cpo-W*
                W       Don't overwrite a readonly file.  When omitted, ":w!"
                        overwrites a readonly file, if possible.

:set compatibleは、すべてのcpoフラグをオンにします。 :set cpo+=Wまたはset cpo-=Wを使用すると、Wフラグのみを変更できます。

2
mosvy