Por que posso modificar um arquivo somente leitura?

42

Pergunta curta:

Por que podemos manipular um arquivo somente leitura no Vim usando :+ w+ q+ !mesmo sem ser um administrador?

Pergunta longa:

Eu tenho um arquivo de texto (myFile.txt) que é somente leitura para todos:

navid@navid-ThinkPad-T530:~/ubuntuTest$ ls -l myFile.txt 
-r--r--r-- 1 navid navid 26 Aug 22 21:21 myFile.txt

Eu posso abri-lo com o Vim sem ter privilégios de administrador:

navid@navid-ThinkPad-T530:~/ubuntuTest$ vi myFile.txt 

Modifico e pressiono: Esc+ :+ w+ q+ Entere vejo esta mensagem de erro:

E45: 'readonly' option is set (add ! to override)

Até agora, tudo faz sentido. Mas quando eu pressiono: Esc+ :+ w+ q+ !+ Enter, o Vim salva as alterações.

Estou usando o Ubuntu 16.04 e VIM 7.4.

Navid Vafaei
fonte
1
@ Zanna Você possui o diretório em que o arquivo está?
23416 Rob
Sim este seria um enorme problema de outra forma :)
Rob
11
Modificar um arquivo e substituí-lo são duas coisas diferentes, com diferentes requisitos de permissão.
David Schwartz
1
Você pode querer dar uma olhada nisso . É, basicamente, responde a sua pergunta e, como @DavidSchwartz corretamente apontou :Modifying a file and replacing a file are two different things
Panagiotis Tabakis
@PanagiotisTabakis Very nice encontrar este é brilhante .. chmod para tornar o arquivo de leitura e escrita e voltar se você possui-lo .. love it :)
Rob

Respostas:

58

Como o @Rob já mencionado , você só pode fazer isso se tiver acesso de gravação ao diretório que contém o arquivo. Tentar fazer o mesmo com um arquivo, por exemplo, /etcfalhará.

Quanto a como isso vim é feito, ele exclui o arquivo e o recria. Para testar isso, criei um arquivo de propriedade root:

echo foo | sudo tee fff

E, em seguida, continue editando o arquivo vimda maneira que você descreve, mas anexando o processo stracepara ver o que está acontecendo:

strace vim fff 2> strace.out

Eu então verifiquei strace.oute encontrei:

unlink("fff")                           = 0
open("fff", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 4
write(4, "foasdasdao\n", 11)            = 11

Portanto, o arquivo foi excluído primeiro ( unlink("fff")), então um novo arquivo com o mesmo nome foi criado ( open("fff", O_WRONLY|O_CREAT|O_TRUNC, 0644)) e as modificações que eu fiz foram gravadas nele ( write(4, "foasdasdao\n", 11)). Se você tentar fazer isso em casa, verá que, depois de editá-lo vim, o arquivo agora pertence a você e não é root.

Portanto, estritamente falando, vimnão está editando um arquivo ao qual você não tem acesso de gravação. Ele está excluindo um arquivo de um diretório ao qual você tem acesso de gravação e, em seguida, criando um novo arquivo ao qual, novamente, você tem acesso de gravação.

terdon
fonte
8
@CCJ é uma operação de gravação no diretório, mas não no arquivo, não. As operações de gravação em arquivos são aquelas que alteram o conteúdo do arquivo. Da mesma forma, a criação / exclusão de arquivos são operações de gravação no diretório, pois você está alterando seu conteúdo.
terdon
2
Além disso, é uma ordem perigosa de operações. Seria mais seguro gravar a substituição em um novo nome de arquivo e depois usá rename(2)-lo para substituir o arquivo antigo. Então não há janela de tempo em que seus dados não existam no disco.
Peter Cordes
5
@PeterCordes hum, OK. Você pode encaminhar suas reclamações para os desenvolvedores do vim. Eu nem uso, estou no campo da emacs.
terdon
3
@CCJ Excluir um arquivo é uma operação de gravação no diretório que o contém, não no próprio arquivo. É perfeitamente intuitivo que, se você estiver encarregado de um diretório (por exemplo, tenha acesso de gravação a ele), possa controlar o que está nele, e o proprietário de um arquivo individual não deverá substituir você.
fkraiem
16

Desde que você possua o diretório pai, poderá remover ou substituir um arquivo, independentemente da permissão, pois é possível alterar o conteúdo do diretório :).

Experimente com outro comando como rm, ele solicitará, mas você ainda poderá fazê-lo. Torne o diretório não gravável e isso deve pará-lo.

Adição:

Apenas tentei, mas enquanto eu possuir o arquivo, ainda posso modificá-lo, mesmo com a pasta somente leitura. No entanto, quando altero a propriedade para root: root, ele não pode abrir o arquivo para gravação. Então, resolve os arquivos modificadores pertencentes ao root (ou a outra pessoa)

Roubar
fonte
7
Parece que o VIM escolhe várias estratégias, incluindo reescrever no local ou desvincular + escrever um novo arquivo.
Peter Cordes
3
@ PeterCordes Sim Aparentemente, será muito difícil fazer o que você manda :) muito esperto. :)
Rob
16

Usando w!você, você está removendo o arquivo original ( que você tem permissão para fazer ) e escrevendo sua versão.

Quando você tem acesso de gravação a um diretório, pode: criar, mover ou excluir arquivos nesse diretório.

$ mkdir foo
$ echo hi > foo/file
$ chmod 777 foo
$ chmod 700 foo/file
$ ls -l foo/file 
-rwx------ 1 ravexina ravexina 7 Aug 31 03:19 foo/file

Agora, deixe-me mudar de usuário e alterar o arquivo

$ sudo -u user2 -s
$ vi foo/a # save using w! (I wrote into the file bye)
$ ls -l foo/a
-rwx------ 1 user2 user2 7 Aug 31 03:20 foo/file

Agora veja o que está lá:

$ cat foo/file
bye
Ravexina
fonte
10

Veja :help write-readonly:

                                                        write-readonly
When the 'cpoptions' option contains 'W', Vim will refuse to overwrite a
readonly file.  When 'W' is not present, ":w!" will overwrite a readonly file,
if the system allows it (the directory must be writable).

Como você possui permissões de gravação no diretório (o que significa que você pode criar, excluir ou renomear arquivos nele), o sistema permite isso.


O valor padrão de cpoptionsnão contém W:

                                                'cpoptions' 'cpo' cpo
'cpoptions' 'cpo'       string  (Vim default: "aABceFs",
                                 Vi default:  all flags)
                        global
muru
fonte
2

Este é o aviso do VIM para você que pode ser relativamente importante, considerando como as permissões funcionam no UNIX. A aparente falta de intuitividade disso ocorre porque os sistemas de arquivos UNIX têm permissões para o arquivo armazenado no nó i do arquivo. A estrutura de diretórios é de alguma forma separada e está vinculando apenas esses nós-i. Os diretórios também têm suas permissões que indicam se você pode vincular / desvincular arquivos nele ou lê-lo ou passar para subdiretórios. Esse design permite que o mesmo arquivo possa aparecer em vários locais diferentes na estrutura de diretórios (por meio de links físicos). Ao dizer "adicionar! Para substituir", o VIM está tentando avisá-lo de que o arquivo original será desvinculado (portanto, permanecerá intocado em todos os outros lugares) e o novo arquivo será criado e vinculado ao local original na estrutura de diretórios. Caso a contagem de links do arquivo original diminua para zero, o arquivo original será liberado, mas, se não, você estará efetivamente clonando o arquivo. A abertura do arquivo também conta como link, por isso, se algum programa abriu o arquivo e você concorda em "adicionar! Substituir", o programa não verá as alterações feitas no arquivo por você com o VIM. O arquivo só é desvinculado do diretório pelo VIM e, após fechar o arquivo por outro programa, o arquivo será liberado, a menos que tenha sido vinculado a outro lugar.

Observe que no Windows, as permissões para arquivos são armazenadas no diretório, portanto, do ponto de vista do paradigma de permissões do Windows, esse comportamento do vim pode realmente parecer estranho. Para gravar no arquivo, o Windows logicamente também pode verificar algumas permissões de diretório, mesmo permissões de superdiretório. Como dito acima, no UNIX, as permissões de diretório são irrelevantes para a manipulação do arquivo na medida em que você foi capaz de listá-lo e abri-lo (ou seja, havia x para todos os super-diretórios). O arquivo aberto no UNIX pode não ter mais o nome do arquivo se ele tiver sido desvinculado de todos os diretórios após a abertura.

Por exemplo, você possui file / home / user1 / foo e é o mesmo arquivo (por exemplo, com link direto para) / home / user2 / foo, e o arquivo não pode ser gravado por ninguém e, atualmente, é aberto pelo programa P (leitura / gravação aberta por programa iniciado pela raiz). Se o usuário1 o abrir com o vim e sobrescrever, ele fará sua própria cópia e não verá mais o arquivo original. Se subseqüentemente o usuário2 abrir seu link com o vim e gravar nele, ele será desvinculado novamente e ele criará outra cópia. O programa P ainda verá o arquivo original e pode ler ou gravar livremente nele. Assim que o programa fechar o arquivo, o arquivo desaparecerá (será liberado pelo sistema de arquivos).

ludvik02
fonte
2

O processo do seu editor vim e seu arquivo carregam seu

 getpwnam("navid")->pw_uid

propriedade para que você também possa desembolsar

 :!chmod +w %

e você pode adivinhar que era uma vez o mais simples

 :!rm %

(exigindo apenas + w, sem permissão para desvincular. e nem mesmo propriedade) tornou-se muito frequente para alguém digitar, para que o vim fosse reprogramado para oferecer automaticamente e, mediante solicitação, executar automaticamente tal operação.

Tente substituir o de sua irmã mais velha

 /home/whoopi/.profile

como mero navid e apostas, seu vim lhe dá a recusa desejada.

Roman Czyborra
fonte
Obrigado @Zanna pela edição do código, mesmo que isso me custe um pouco de reputação para os novatos, embora merecidamente.
Roman Czyborra
1

Esta não é exatamente uma resposta, mas se você realmente deseja definir um arquivo para que ninguém possa alterá-lo ou excluí-lo, você pode torná-lo imutável.

Normalmente, mesmo quando um arquivo pertence à raiz, você ainda pode excluí-lo se tiver permissões de gravação na pasta. Mas quando você torna o arquivo imutável, mesmo o root não pode modificá-lo ou excluí-lo.

Para tornar um arquivo imutável (você precisa sudo):

sudo chattr +i myFile.txt

Você pode ver isso com lsattr(a letra ino resultado):

$ lsattr myFile.txt
----i--------e-- myFile.txt

Para tornar o arquivo normal novamente:

sudo chattr -i myFile.txt

Para esclarecer: Quando um arquivo é imutável, ele não pode ser excluído, renomeado, modificado ou vinculado diretamente.

Vale a pena ler man chattr, porque os arquivos podem ter vários atributos úteis.

Você também pode achar útil "exclusão restrita". Se colocado em uma pasta (não em um arquivo), isso significa que quem cria um arquivo dentro da pasta tem permissão para modificar ou excluir esse arquivo, mas ninguém mais é (exceto raiz). A pasta /tmptem este sinalizador definido. Você pode ver isso com a tbandeira em /tmp:

$ ls -l --directory /tmp
drwxrwxrwt 10 root root 4096 Sep  6 09:00 /tmp

Para definir ou remover o sinalizador de exclusão restrita em uma pasta:

chmod +t myFolder      # Add the restricted deletion flag.
chmod -t myFolder      # Remove the restricted deletion flag.
Paddy Landau
fonte