É possível usar “/” em um nome de arquivo?

111

Eu sei que isso não é algo que deveria ser feito, mas existe uma maneira de usar o caractere de barra que normalmente separa os diretórios dentro de um nome de arquivo no Linux?

subcan
fonte
1
Eu acho que você pode modificar o nome de um arquivo usando o acesso direto à partição do seu disco rígido e patch em um caractere '/' em algum lugar. O que acontece é uma questão interessante ... provavelmente não é o que você quer.
hochl
1
Mas a resposta curta deve ser: não, isso não é algo que deveria ser feito :-)
Simeon Visser
Hackear uma barra no nome do arquivo na entrada do diretório no FS conta? Não seria recomendado; você não será capaz de acessar o arquivo, nunca.
Jonathan Leffler
35
Isso me lembra de quando meu amigo criou um arquivo chamado *e perguntou: "Como faço para remover um arquivo?" Eu respondi, rmseguido pelo nome do arquivo. Bem, você sabe o restante.
David Heffernan
1
Para novos usuários do Linux, quando você não tem certeza sobre uma expressão ou nome de arquivo, acho que é uma boa prática usar lspara listar os arquivos que você deseja remover e, em seguida, alterar o lscomando para rmdepois.
Dave F

Respostas:

129

A resposta é que você não pode, a menos que seu sistema de arquivos tenha um bug. Aqui está o porquê:

Há uma chamada de sistema para renomear seu arquivo definido em fs/namei.cchamado renameat:

SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname)

Quando a chamada do sistema é invocada, ela faz uma pesquisa de caminho ( do_path_lookup) no nome. Continue rastreando isso, e chegaremos a link_path_walkqual tem o seguinte:

static int link_path_walk(const char *name, struct nameidata *nd)
{
       struct path next;
       int err;
       unsigned int lookup_flags = nd->flags;

       while (*name=='/')
              name++;
       if (!*name)
              return 0;
...

Este código se aplica a qualquer sistema de arquivos. O que isso significa? Isso significa que se você tentar passar um parâmetro com um '/'caractere real como o nome do arquivo usando os meios tradicionais, ele não fará o que você deseja. Não há como escapar do personagem. Se um sistema de arquivos "suporta" isso, é porque:

  • Use um caractere Unicode ou algo que se pareça com uma barra, mas não é.
  • Eles têm um bug.

Além disso, se você fez entrar e editar os bytes para adicionar um caractere de barra em um nome de arquivo, coisas ruins aconteceriam. Isso porque você nunca poderia se referir a este arquivo pelo nome :( já que sempre que o fizesse, o Linux assumiria que você estava se referindo a um diretório inexistente. Usar a técnica 'rm *' também não funcionaria, pois o bash simplesmente a expande para o nome do arquivo. Mesmo rm -rfnão funcionaria, já que um simples traço revela como as coisas acontecem sob o capô (abreviado):

$ ls testdir
myfile2 out
$ strace -vf rm -rf testdir
...
unlinkat(3, "myfile2", 0)               = 0
unlinkat(3, "out", 0)                   = 0
fcntl(3, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
close(3)                                = 0
unlinkat(AT_FDCWD, "testdir", AT_REMOVEDIR) = 0
...

Observe que essas chamadas para unlinkatfalhariam porque precisam se referir aos arquivos pelo nome.

Robert Martin
fonte
8
Além disso, observe que pelo menos e2fsckconsidera qualquer nome de arquivo como um nome de arquivo ilegal que deve ser corrigido - consulte a fonte . Portanto, se, de alguma forma, acabar com um nome de arquivo com barras, você pode usar fsckpara corrigir o problema.
ehabkost
4
@ehabkost Qualquer nome de arquivo? Parece um bug em e2fsck: p
flarn2006
36

Você pode usar um caractere Unicode exibido como "/" (por exemplo, este glifo aparentemente redundante ), supondo que seu sistema de arquivos o suporte.

Blackle Mori
fonte
42
Sim, precisamente: apenas /, que é U + 002F SOLIDUS, é proibido. Existem muitos outros candidatos adequados: ⁄ é U + 2044 FRACTION SLASH; ∕ é U + 2215 DIVISION SLASH; ⧸ é U + 29F8 BIG SOLIDUS; / É U + FF0F FULLWIDTH SOLIDUSe ╱ é U + 2571 is BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT. Tudo funcionaria admiravelmente!
tchrist
2
Mas e se o usuário usar esses caracteres reais em seus nomes de arquivo / diretório? Precisamos de uma solução de escape genérica. Pena que o código normal do Linux não suporta nenhum, já que ele corresponde literalmente ao ASCII 0x2F. ASCII é uma grande proibição desde pelo menos 20 anos. (Unicode 1.0 é de 1991!)
Evi1M4chine
@tchrist eu prefiro não depender do Unicode. então eu provavelmente preferiria um delimitador de vários caracteres como ---. sua escolha de delimitador pode usar um caractere diferente e variar o número de repetições.
Trevor Boyd Smith
Para uma lista de possíveis substituições em vários caracteres, que são proibidas em diferentes sistemas de arquivos, dê uma olhada em minha resposta: stackoverflow.com/a/61448658/4575793
Cadoiz
9

Depende de qual sistema de arquivos você está usando. De alguns dos mais populares:

Nicolas
fonte
1
não depende apenas do sistema de arquivos, chamadas de sistema em todos os sistemas * nix analisarão o / como um componente da árvore de diretórios.
Blackle Mori
2
O caractere de barra é embutido no kernel, independente do sistema de arquivos (tente fazer grep -r "'/'" *na fonte do kernel)
Robert Martin
20
@tchrist Com licença. "Barra para frente" é uma forma completamente aceitável de se referir ao caractere de barra para deixar bem claro a qual barra se refere. Às vezes as pessoas ficam confusas: P
Robert Martin
2
Hah, mas @tchrist também tem razão, eu acho. Por que avançar 'implica' / 'e' voltar 'implica' \ '? A melhor explicação que tenho até agora é que se escrito com uma caneta começando em uma linha, de baixo para cima, '/' move-se para a direita ou 'para frente' e '\' move-se para 'esquerda' ou 'para trás', ao ler / escrever da esquerda para a direita. Eu realmente não gosto dessa explicação, em parte porque nem sempre escrevo meus personagens de baixo para cima e subo. Acho que começar de cima e descer enquanto escrevo um personagem geralmente flui melhor.
Jesse W. Collins,
4
@jwso Este é um ponto totalmente lateral, mas é uma linguagem canônica padrão. Slash não é o que o Unicode chama de símbolos que se parecem com esses, ele os chama de solidus, mas "\" é um solidus reverso, que é sinônimo de reverso, portanto, barra invertida. Mas se for preciso uma justificativa, para frente e para trás são a direção em que a linha se inclina ou deve cair, com direção baseada na direção da escrita (da esquerda para a direita). Ele se inclina ou deve cair <== ou para trás se for semelhante a "\" e ==> ou para frente se for semelhante a "/".
Stuart R. Jefferys
4

Apenas com uma codificação acordada. Por exemplo, você pode concordar que %será codificado como %%e que %2Fsignificará a /. Todo software que acessasse este arquivo teria que entender a codificação.

David Schwartz
fonte
19
"aquilo que chamamos de barra por qualquer outro nome teria o mesmo cheiro" - Shakespeare
Robert Martin
1

A resposta curta é: Não, você não pode. É uma proibição necessária devido à forma como a estrutura do diretório é definida.

E, como mencionado, você pode exibir um caractere Unicode que "se parece" com uma barra, mas isso é o máximo que você consegue.

keyer
fonte
1

Em geral, é uma má ideia tentar usar caracteres "ruins" em um nome de arquivo; mesmo que você o gerencie de alguma forma, ele tende a dificultar o uso do arquivo posteriormente. O separador do sistema de arquivos simplesmente não vai funcionar, então você vai precisar escolher um método alternativo.

Você já pensou em codificar o URL e usá-lo como nome de arquivo? O resultado deve ser bom como um nome de arquivo e é fácil reconstruir o nome da versão codificada.

Outra opção é criar um índice - criar o nome do arquivo de saída usando o método que você quiser - nomes numerados sequencialmente, hashes SHA1, qualquer que seja - e então escrever um arquivo com o par nome de arquivo / URL gerado. Você pode salvá-lo em um hash e usá-lo para fazer uma pesquisa de URL para nome de arquivo ou vice-versa com a versão reversa do hash, e pode escrever e recarregar mais tarde, se necessário.

Joe McMahon
fonte