$ inotifywait -m /tmp
Setting up watches.
Watches established.
/tmp/ CREATE file.ext.filepart
/tmp/ OPEN file.ext.filepart
/tmp/ MODIFY file.ext.filepart
/tmp/ CLOSE_WRITE,CLOSE file.ext.filepart
/tmp/ CREATE file.ext
/tmp/ DELETE file.ext.filepart
Transcrição da execução
$ echo hello >/tmp/file.ext.filepart
$ ln /tmp/file.ext.filepart /tmp/file.ext
$ rm /tmp/file.ext.filepart
Mover um arquivo gera um evento move
, mas a criação de um link físico gera o mesmo evento create
da criação de um novo arquivo vazio (como mkfifo
e outras formas de criar arquivos).
Por que o servidor SCP ou SFTP cria um link físico e, em seguida, remove o arquivo temporário em vez de mover o arquivo temporário para o local? No código-fonte do OpenSSH (portátil 6.0), em sftp-server.c
, na função process_rename
, vejo o seguinte código (reformatado e simplificado para ilustrar a parte que quero mostrar):
if (S_ISREG(sb.st_mode)) {
/* Race-free rename of regular files */
if (link(oldpath, newpath) == -1) {
if (errno == EOPNOTSUPP || errno == ENOSYS) {
/* fs doesn't support links, so fall back to stat+rename. This is racy. */
if (stat(newpath, &st) == -1) {
rename(oldpath, newpath) == -1)
}
}
} else {
unlink(newpath);
}
}
Ou seja: tente criar um link físico do nome do arquivo temporário para o nome do arquivo desejado e, em seguida, remova o arquivo temporário. Se a criação do link físico não funcionar porque o sistema operacional ou o sistema de arquivos não suportam isso, recorra a um método diferente: teste se o arquivo desejado existe e, se não, renomeie o arquivo temporário. Portanto, o objetivo é renomear o arquivo temporário para seu local final sem arriscar sobrescrever um arquivo que possa ter sido criado enquanto a cópia estava em andamento. A renomeação não seria feita porque rename
sobrescreve o arquivo de destino, se existir.