Como o “cp” lida com arquivos abertos?

15

Estou tendo dois diretórios separados. O usuário carrega um arquivo no primeiro. Existe um cronjob em execução em segundo plano que copia os arquivos a cada 5 minutos para o segundo diretório.

O que acontece se o usuário não tiver concluído o upload e o cronjob copiar os arquivos? Observe que os dois diretórios pertencem a usuários diferentes, o cronjob é executado como raiz.

Abafado
fonte
leia este post para ver o que acontece neste caso: unix.stackexchange.com/questions/49299/...
Serge
Obrigado, bom post que você escreveu. Mas minha pergunta era mais relacionada ao cp, não ao tratamento de arquivos linux em geral. Embora o cp talvez verifique se o arquivo ainda está aberto e aguarde até que seja fechado ou algo assim.
entupido
Não cp, não esperará até o upload completo do arquivo. Como esperamos que a taxa de transferência de rede seja mais baixa do que apenas copiar o arquivo de um local para outro dentro do mesmo host, em algum momento cpatingirá o final do arquivo atual e interromperá a cópia. A solução para o seu problema pode ser simples: primeiro, o usuário carrega o arquivo com algum nome de arquivo especialmente desconectado (por exemplo, anexado com .(ponto)). Quando a transferência é concluída, o usuário o renomeia para o nome original. para os arquivos que não estão iniciando ...
Serge

Respostas:

17

cpnão sabe sobre arquivos abertos. Portanto, se o primeiro usuário enviar um arquivo grande e o cronjob (ou qualquer outro processo) começar a copiar esse arquivo, ele copiará apenas o que já foi gravado. Você pode pensar sobre isso desta maneira - cpfaz uma cópia do que está atualmente no disco, não importa se o arquivo está completo. Caso contrário, você não poderá copiar os arquivos de log, por exemplo.

Krzysztof Adamski
fonte
Obrigado, é o que eu queria saber! Existe uma maneira simples de evitar isso? Verifiquei a página de manual do cp, mas não encontrei nada de útil.
entupido
Para fazer o que exatamente? Para copiar todos os arquivos, exceto os abertos? Eu não acho que exista uma maneira fácil de fazer isso (além de escrever seu próprio script que usa fuser+ cp. Essa cópia seria realmente pouco confiável. Não copiará nenhum arquivo que seja aberto no editor de texto, por exemplo.
Krzysztof Adamski
@ Fofo, talvez no seu cronjob você possa listar arquivos abertos lsof? A saída disso deve ser fácil de processar. Você pode filtrar os arquivos que estão sendo abertos (digamos, por uma instância de cp) para gravação.
Wojtek Rzepala 11/11/12
@WojtekRzepala, vou dar uma olhada nisso, obrigado. Talvez eu vou escrever um pequeno script que é executado pelo cron
entupido
@ Stuffy: Lembre-se de que pode não ser realmente confiável se não for executado pelo usuário root (o mesmo problema é fuserclaro), pois essa ferramenta pode não mostrar todos os arquivos.
Krzysztof Adamski
7

cpnão sabe quais outros programas podem ter os arquivos abertos. Não há mágica cp. O design do unix evita propositalmente colocar qualquer tipo de bloqueio nos arquivos, a menos que haja um motivo convincente (o que significa que o kernel precisa dele). Neste tópico, consulte O redirecionamento de saída para um arquivo aplica um bloqueio no arquivo?

Tais situações, em que um arquivo é produzido por um produtor e, uma vez concluído, consumido por um consumidor, são comuns. A maneira usual de lidar com isso é fazer com que o produtor grave um arquivo temporário que o consumidor não procurará; depois que o produtor terminar, mova o arquivo para um local onde o consumidor o encontre. Mover um arquivo (no mesmo sistema de arquivos) é uma operação atômica: em algum momento, para o consumidor, o arquivo muda de não estar lá para estar lá.

Portanto, organize seu trabalho de upload para mover os arquivos para um diretório diferente quando terminar de fazer o upload. Aponte o trabalho cron para esse diretório diferente.

Gilles 'SO- parar de ser mau'
fonte
6

Parece que você deseja fazer um trabalho de sincronização de diretório.

Porque a opção -u, --update decp

copiar somente quando o arquivo SOURCE for mais novo que o arquivo de destino ou quando o arquivo de destino estiver ausente

Portanto, você pode adicionar um cronjob como o cp -auv SOURCEDIR/* DESTDIRque copiará os arquivos cuja hora de modificação foi alterada. Isso significa DESTDIRque, eventualmente, obterá a cópia completa enquanto o upload terminar.

rsyncpode fazer o mesmo trabalho. por exemplo rsync -av SOURCEDIR/ DESTDIR,.

Embora a opção -a seja aplicada, alguns atributos especificados (por exemplo, propriedade) só podem ser preservados pelo superusuário.

Veja man cp, man rsyncpara detalhes.

Edw4rd
fonte
Apenas tome cuidado com as entradas recentes na pasta de destino - elas podem não ser arquivos completos.
dubiousjim