Aqui está um comportamento estranho mklink
que encontrei no Windows desde o Vista. Suspeito que possa haver um defeito mklink
ou até mesmo tão profundo quanto o driver do sistema de arquivos NTFS, mas o comportamento precisa de alguma explicação. Esse comportamento foi encontrado no Windows 7 e 10, respectivamente.
Suponha que temos um diretório em um volume NTFS (façaNÃOtente isso em qualquer coisa, menos em um volume que você está criando para esse único propósito!) e em um arquivo nomeado bar.txt
dentro dele.
md F:\1
echo foo > F:\1\bar.txt
Agora emita o seguinte comando (via prompt privilegiado):
mklink F:\1:bar F:\1\bar.txt
... o que deve lhe dar:
symbolic link created for F:\1:bar <<===>> F:\1\bar.txt
Não se preocupe, eusaberisso ébobagem. Mas foi o resultado de um teste para saber se um fluxo de dados alternativo (ADS) poderia se tornar um ponto de nova análise. Acreditei que não, porque um fluxo de dados alternativo só tem um nome, um tamanho e - bem - os dados dentro dele. Ao contrário de um arquivo ou diretório, ele não possui atributos de arquivo ou carimbos de data/hora próprios e, portanto, não haveria nenhum atributo para designar o ADS como ponto de nova análise (o que de outra forma acontece através dos atributos do arquivo). Ou dito de outra forma: os pontos de nova análise só podem referir-separaentradas de diretório (via $Extend\$Reparse
), enquanto ADS estão vinculados a entradas de diretório.
O resultado do comando acima é este:
F:\>dir /r
Volume in drive F is TEST
Volume Serial Number is 24F3-8A7D
Directory of F:\
2018-04-03 20:47 <SYMLINKD> 1 [F:\1\bar.txt]
0 1:bar:$DATA
0 File(s) 0 bytes
1 Dir(s) 4,244,283,392 bytes free
Não é novidade que a tentativa de mudar para este diretório não funciona e resultaThe directory name is invalid.
Da mesma forma, a tentativa de excluir o ponto de nova análise usando junction -d
(do Sysinternals Suite) ou usando fsutil reparsepoint delete
falha com o mesmo erro. Apenas inspecionar os dados do ponto de nova análise me dá algo em que me agarrar:
F:\>fsutil reparsepoint query F:\1
Reparse Tag Value : 0xa000000c
Tag value: Microsoft
Tag value: Name Surrogate
Tag value: Symbolic Link
Reparse Data Length: 0x00000044
Reparse Data:
0000: 18 00 20 00 00 00 18 00 00 00 00 00 46 00 3a 00 .. .........F.:.
0010: 5c 00 31 00 5c 00 62 00 61 00 72 00 2e 00 74 00 \.1.\.b.a.r...t.
0020: 78 00 74 00 5c 00 3f 00 3f 00 5c 00 46 00 3a 00 x.t.\.?.?.\.F.:.
0030: 5c 00 31 00 5c 00 62 00 61 00 72 00 2e 00 74 00 \.1.\.b.a.r...t.
0040: 78 00 74 00 x.t.
Agora, minha pergunta é o que aconteceu aqui e como faço para me livrar desse ponto de nova análise novamente com ferramentas integradas do Windows (ou, na sua falta, externas)?Pontos de bônus por poder responder o que aconteceu com o arquivo dentro da pasta 1
e divulgar sua metodologia.
Minha teoria de trabalho até agora é a seguinte:
mklink
cria o "arquivo"F:\1:bar
e é bem-sucedido (presumivelmente viaCreateFile()
).mklink
defineREPARSE_DATA_BUFFER
o "arquivo" criado que não pode funcionar porque é um ADS em um diretório. Então, internamente, o que acontece é que o driver do sistema de arquivos define o buffer de dados de nova análise no diretório.
O resultado é o que vemos. O que me incomoda aqui é que normalmente você não consegue controlar um diretório sem especificar um sinalizador específico. Portanto, não apenas criamos mklink
um link simbólicoem um diretóriopara um arquivo, também evitamos a necessidade de especificar FILE_FLAG_BACKUP_SEMANTICS
.
A documentação FILE_FLAG_BACKUP_SEMANTICS
abaixoCreateFile
lê:
Você deve definir esse sinalizador para obter um identificador para um diretório. Um identificador de diretório pode ser passado para algumas funções em vez de um identificador de arquivo. Para obter mais informações, consulte a seção Comentários.
Para reproduzir eu recomendo fortemente que vocênãotente isso em uma unidade NTFS existente, mas em vez disso, crie uma nova usando oImDiskDriver de disco RAM e a imdisk
ferramenta de linha de comando que o acompanha (via prompt privilegiado):
imdisk -a -t vm -p "/fs:ntfs /q /y /v:TEST" -s 4G -m F:
(altere os parâmetros como achar melhor. -m
indica uma letra de unidade e -s
o tamanho do disco RAM.)