vimで読み取り専用モードをオーバーライドする方法は? [コピー]

vimで読み取り専用モードをオーバーライドする方法は? [コピー]

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

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

答え1

Vimでこれを行うときにw!実際に行われることは、ファイルの所有者によって異なります。

  • あなた(現在のユーザー)がファイルの所有者である場合、Vimはファイルを書き換える前に書き込み権限を変更します。その後、書き込み権限を削除し、権限ビットを元の状態に戻します。

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

Vimはファイルに書き込むことができる高い権限を全く取得しません。

上記のメカニズムは、読み取り専用ファイルに書き込む必要があるすべてのプログラムが選択する必要がある使用可能なオプションの1つです(たとえば、ファイルへの書き込み中に一時的に権限を変更するか、ファイルを削除して新しいファイルを作成します)。 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)

これはファイルの権限を変更して書き込み可能にし(S_IWUSRフラグ付きchmod())、バッファを書き込みます。

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

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

答え2

Vimは追加の権限を取得できません。次の理由で設定できる:w!内部オプションをオーバーライドします。'readonly'

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

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


Vimを開くユーザーに書き込みアクセス権がない場合は、実際にアクセス権を取得するには、:w !sudo tee >/dev/null fileこのトリックを直接使用するか、類似のプラグインを介して使用する必要があります。Sudo編集

答え3

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

VIMが使用するトリックは、ファイルを削除して新しいファイルを作成することです。

ソースコードを読み取らなくても、VIMがどのように使用しているかを確認することで確認できます。アイノード番号前と後:

$ 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

inode 番号が変更され、新しいファイルが編集したファイルと異なることを示します。


ちなみに、現在の設定は非常に短いです。

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

答え4

vimがvi互換モードの場合:w!はバッファの読み取り専用モードのみを上書きしますが、ファイル権限を前後に変更したり、他のファイル名を元の名前に変更して権限をバイパスしたり、他の予備操作を試みたりしません。時間が重要です。

IMHO これが唯一正しい動作です。これを制御するフラグは/Wから出てきます。から:cpoptionscpo: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フラグがオンになります。フラグをW使用または変更できます。:set cpo+=Wset cpo-=W

関連情報