Faz 'ln -sf' sobrescrever arquivos existentes que são apenas links simbólicos

4

Do coreutils ln manual:

Normally ln does not remove existing files. Use the --force (-f) option to remove them
unconditionally, the --interactive (-i) option to remove them conditionally,
and the --backup (-b) option to rename them.

$ mkdir output

Eu posso entender isso não:

$ ln -sT /etc/passwd output
ln: failed to create symbolic link ‘output’: File exists

Mas por que a adição de -f também falha:

$ ln -sfT /etc/passwd output
ln: ‘output’: cannot overwrite directory

O -f sobrescreve arquivos existentes que são apenas links simbólicos, mas não arquivos de outros tipos (diretórios, arquivos regulares, ...)?

Pode o -T ser usado quando o último argumento (ou seja, o argumento do arquivo de destino) é um diretório existente, com a intenção de sobrescrever o diretório em um link?

    
por Tim 03.07.2016 / 02:55

2 respostas

8

Ele pode remover arquivos, mas os diretórios não são "arquivos".

➜  lab touch file        
➜  lab mkdir dir
➜  lab ln -sfT /home file
➜  lab ln -sfT /home dir 
ln: dir: cannot overwrite directory

Isso é visto na fonte :

  if (remove_existing_files || interactive || backup_type != no_backups)
    {
      dest_lstat_ok = (lstat (dest, &dest_stats) == 0);
      if (!dest_lstat_ok && errno != ENOENT)
        {
          error (0, errno, _("failed to access %s"), quoteaf (dest));
          return false;
        }
    }
[...]
  if (dest_lstat_ok)
    {
      if (S_ISDIR (dest_stats.st_mode))
        {
          error (0, 0, _("%s: cannot overwrite directory"), quotef (dest));
          return false;
        }
      if (interactive)
        {
          fprintf (stderr, _("%s: replace %s? "), program_name, quoteaf (dest));
          if (!yesno ())
            return true;
          remove_existing_files = true;
        }

dest_lstat_ok boolean que começa como false se torna true, a primeira instrução if é chamada desde remove_existing_files Isso é verdade devido ao sinal --force , que por sua vez permite que a segunda declaração if seja verificada. Ele se recusa a remover diretórios porque está esperando um arquivo .

Se você não definir o -T , o que faz com que ln não trate o diretório como não sendo um diretório , o ln criaria um link simbólico sob o diretório com o nome da base da fonte.

    
por 03.07.2016 / 03:52
7

No UNIX, os diretórios são especiais (eu me sinto canalizando The Church Lady do SNL). Os diretórios contêm outros arquivos, portanto, excluí-los requer uma operação diferente. Mesmo quando um diretório está vazio, ele ainda tem dois arquivos ( . e .. ), portanto, excluir um diretório não pode ser feito até que esteja realmente vazio e as contagens de links nos arquivos relevantes tenham sido atualizadas.

Nos primórdios do UNIX (minha primeira experiência foi com a 6ª edição da Bell Labs), havia dois comandos diferentes ( rm e rmdir ) para arquivos e diretórios comuns, o que refletia o fato de que eles eram dois diferentes chamadas do sistema. rm foi simples, apenas removeu a entrada cujo nome você deu a partir do diretório e diminuiu a contagem de referência no arquivo para o qual ela apontou (obviamente, o arquivo não é realmente excluído, a menos que a contagem de referência seja 0). rmdir exigiu muito mais (não na aplicação, mas na chamada do sistema), tinha que ir para o diretório e encontrar as entradas . e .. , ir para esses inodes e decrementar a contagem de ref. em seguida, remova a entrada no pai e diminua a contagem de ref (a mesma que acabou de decrementar para . no próprio diretório, que deve ser 0). Tudo isso abrangia vários setores de disco diferentes e, portanto, tinha que ser cuidadosamente ajustado para tornar a possibilidade de um aborto (por exemplo, travamento do sistema) ser recuperável em qualquer ponto pelo fsck.

Naturalmente, em sistemas UNIX mais modernos, as restrições do hardware (isto é, 64 KBbyte tamanho do programa, é um "K") foram facilitadas e agora você pode fazer rm -r e um A maior parte da natureza básica especial dos diretórios é menos aparente, mas ainda está lá. Lembro-me de precisar excluir uma árvore grande na máquina da 6ª edição que envolvia entrar em cada diretório, excluir todos os arquivos, voltar para o pai e fazer rmdir e essencialmente fazer toda a recursão em todas as árvores de diretório manualmente. Nós pensamos sobre um roteiro para ajudar nisso, mas ele surgiu tão raramente naqueles dias e foi suficientemente perigoso que decidimos que exigir que alguém participasse de todo esse esforço ajudaria a evitar erros catastróficos.

A primeira vez que você recebe uma pergunta que diz "Eu digitei ' sudo rm -rf / ' em vez de ./ como eu me recupero?" você pode entender porque estávamos sendo cautelosos.

    
por 03.07.2016 / 05:25

Tags