Para lidar com nomes de arquivos arbitrários (incluindo os que contêm caracteres de nova linha), o truque comum é encontrar arquivos dentro de .//.
em vez de .
. Como //
não pode ocorrer normalmente ao percorrer a árvore de diretórios, você tem certeza de que //
sinaliza o início de um novo nome de arquivo na saída find
(ou aqui lsattr -R
).
lsattr -R .//. | awk '
function process() {
i = index(record, " ")
if (i && index(substr(record,1,i), "i"))
print substr(record, i+4)
}
{
if (/\/\//) {
process()
record=$0
} else {
record = record "\n" $0
}
}
END{process()}'
Observe que a saída ainda será separada por nova linha. Se você precisar pós-processá-lo, terá que adaptá-lo. Por exemplo, você poderia adicionar um -v ORS='xargs -r0
'
para poder alimentá-lo com lsattr -R
do GNU.
Observe também que find
(pelo menos 1.42.13) não pode reportar os flags de arquivos cujo caminho é maior que PATH_MAX (geralmente 4096), então alguém poderia ocultar um arquivo imutável, movendo seu diretório pai (ou qualquer um dos componentes do caminho que levam a ele, exceto ele próprio como imutável) para um diretório muito profundo.
Uma solução seria usar -execdir
com -print0
:
find . -execdir sh -c '
a=$(lsattr -d "$1") &&
case ${a%% *} in
(*i*) ;;
(*) false
esac' sh {} \; -print0
Agora, com lsattr
, isso é pós-processável, mas se você pretende fazer algo com esses caminhos, observe que qualquer chamada de sistema em caminhos de arquivo maiores que PATH_MAX ainda falhará e componentes de diretório poderia ter sido renomeado no intervalo.
Se quisermos obter um relatório confiável em uma árvore de diretórios potencialmente gravável por outras pessoas, há mais alguns problemas inerentes ao comando lsattr -R .
que precisaríamos mencionar:
- o caminho
.
atravessa a árvore de diretórios, está sujeito a condições de corrida. Pode-se fazer descer para diretórios fora da árvore de diretórios roteados em lsattr -d file
, substituindo alguns diretórios por links simbólicos no momento certo.
- até
lsattr
tem uma condição de corrida. Esses atributos são aplicáveis apenas a arquivos ou diretórios comuns. Portanto, lstat()
faz um open()
primeiro para verificar se o arquivo é dos tipos corretos e então ioctl()
seguido por open()
para recuperar os atributos. Mas chama O_NOFOLLOW
sem file
(nem O_NOCTTY). Alguém pode substituir /dev/watchdog
por um link simbólico para lstat()
, por exemplo, entre open()
e open(O_PATH|O_NOFOLLOW)
e fazer com que o sistema seja reinicializado. Ele deve fazer fstat()
seguido por openat()
, ioctl()
e %code% aqui para evitar as condições de corrida.