web-dev-qa-db-fra.com

Comment vim écrase le mode lecture seule?

Très souvent, nous constatons que le fichier que nous essayons d'enregistrer dans vim après modification est signalé en lecture seule. La solution consiste à ajouter !wq, j'essaie de comprendre ce qui se passe en interne qui permet au programme vim d'obtenir suffisamment d'autorisations pour écrire le fichier en lecture seule?

Y a-t-il un drapeau interne qui est commuté ou le vim gagne temporairement les privilèges pendant un certain temps?

24
Atul

Lorsque vous faites w! Dans Vim, ce qui se passe réellement dépend de la personne qui possède le fichier.

  • Si vous (l'utilisateur actuel) êtes le propriétaire du fichier, Vim modifiera les autorisations en écriture avant de réécrire le fichier. Il supprime ensuite les autorisations d'écriture pour restaurer les bits d'autorisation à ce qu'ils étaient depuis le début.

  • Si vous n'êtes pas le propriétaire du fichier, mais si vous disposez d'autorisations d'écriture dans le répertoire en cours, Vim supprimera le fichier d'origine et écrit le document dans un nouveau fichier du même nom. Le nouveau fichier se verra alors attribuer les mêmes autorisations que le fichier d'origine, mais vous appartiendra.

À aucun moment, Vim ne bénéficie de privilèges élevés pour pouvoir écrire dans le fichier.

Les mécanismes décrits ci-dessus sont les options disponibles que tout programme qui doit écrire dans un fichier en lecture seule doit choisir (c'est-à-dire modifier temporairement l'autorisation pendant l'écriture dans le fichier, ou supprimer le fichier et en créer un nouveau), et ce que Vim finit par choisir de faire peut en fin de compte dépendre d'un certain nombre de paramètres configurables.

Comme on le voit dans les commentaires ci-dessous, il y a une certaine confusion à propos de ce qui précède. Si vous voulez voir par vous-même ce qui se passe réellement avec votre configuration de Vim sur votre marque particulière d'Unix, je vous recommande de suivre les appels système que Vim fait lors de l'écriture dans un fichier en lecture seule. La façon dont cela est fait dépend de l'Unix que vous utilisez. Sous Linux, cela se fait probablement par ex. strace vim file (Puis modifiez le fichier, enregistrez-le avec w! Et quittez).


C'est le premier cas (sortie de ktrace + kdump sur OpenBSD):

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)

Cela modifie les autorisations sur le fichier afin qu'il soit accessible en écriture (l'indicateur S_IWUSR Utilisé avec chmod()) et y écrit le tampon.

Il définit ensuite les autorisations d'origine:

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

Pour l'autre cas:

Il dissocie (supprime) d'abord le fichier, puis le recrée (avant d'écrire dans le fichier et de modifier les autorisations ultérieurement):

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 ne peut pas obtenir d'autorisations supplémentaires. L'option :w! Remplace simplement l'option interne 'readonly', Qui peut avoir été définie car:

  • vous avez ouvert le fichier via l'option de ligne de commande -R ou avec :view au lieu de :edit, ou :setlocal readonly
  • Vim reconnaît que le fichier ne dispose pas actuellement des autorisations d'écriture

Dans ce dernier cas, une écriture de fichier peut toujours être possible car Vim (par défaut) crée un nouveau fichier puis remplace le fichier d'origine par celui-ci. Cela dépend toujours des autorisations définies de manière à permettre cela.


Pour vraiment gagner des autorisations d'écriture là où l'utilisateur qui a ouvert Vim n'en a pas, l'astuce :w !Sudo tee >/dev/null file Doit être utilisée, soit directement, soit via un plugin comme SudoEdit .

4
Ingo Karkat

Vous ne pouvez jamais écrire dans un fichier sur lequel vous ne disposez pas d'autorisations d'écriture. Cependant, vous pouvez supprimer ce fichier si vous avez des autorisations d'écriture sur le répertoire.

L'astuce que VIM utilise est de supprimer le fichier et d'en écrire un nouveau.

Il est possible de montrer que c'est la méthode VIM utilise sans lire le code source en vérifiant numéro d'inode avant et après:

$ 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

Notez que le numéro d'inode a changé, indiquant que le nouveau fichier n'est PAS le même fichier que celui que vous avez modifié.


FYI Ma configuration actuelle est vraiment courte:

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

Et les paquets Debian installés sont:

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

Lorsque vim est en mode compatible vi,: w! ne remplacera que le mode en lecture seule du tampon, mais n'essaiera pas de modifier les autorisations de fichier dans les deux sens, contournera les autorisations en renommant un fichier différent au nom de l'original ou fera d'autres trucs d'heure amateur.

C'est le seul comportement correct à mon humble avis - le drapeau qui contrôle cela est W de cpoptions/cpo. De :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 activera tous les drapeaux cpo. Vous pouvez modifier uniquement le drapeau W avec :set cpo+=W ou set cpo-=W.

2
mosvy