Se você estiver movendo o arquivo dentro do mesmo sistema de arquivos, então mv
é uma operação atômica . Até certo ponto, o arquivo está no local antigo; depois desse ponto, o arquivo está no novo local. A entrada para o arquivo no diretório antigo é removida e uma nova é adicionada ao novo diretório, em uma única operação. A entrada não é apenas o conteúdo do arquivo, mas todo o inode , incluindo os metadados do arquivo, como o proprietário e as permissões. Não há nenhum ponto em que as permissões sejam modificadas.
Se você estiver movendo o arquivo para um sistema de arquivos diferente , a operação não é atômica: envolve a criação de um novo arquivo e a modificação do conteúdo e dos metadados até que eles correspondam ao arquivo antigo. e removendo o arquivo antigo. Um novo arquivo é sempre criado vazio e pertencente ao usuário que o criou. O criador pode definir as permissões tradicionais do Unix assim que o arquivo é criado, mas não as listas de controle de acesso.
Você pode controlar o proprietário inicial, o grupo e o modo do novo arquivo executando mv
como proprietário e grupo desejados e definindo umask
como o complemento das permissões do arquivo. Aqui está um método shell do Linux, assumindo que o usuário e o grupo existam e tenham um shell estilo Bourne como seu shell de login:
set $(stat -c '%U %G %a' "$original_file")
export user=$1 group=$2 mode=0$3 original_file destination
su "$user" -c 'sg "$group" -c "umask $((07777 & ~mode)) && touch "$destination" && mv -- "$original_file" "$destination"'
Isso é muito complicado, e o arquivo será criado com a propriedade e permissões corretas, mas com conteúdos diferentes, timestamps diferentes, etc. Se você não quiser que o arquivo fique visível até que seja totalmente reproduzido, primeiro mova o arquivo para um diretório temporário no sistema de arquivos de destino que é visível apenas para o root e, em seguida, move o arquivo atomicamente para o local.
d=$(TMPDIR="$(dirname -- "${destination}")" mktemp -d)
chmod 700 "$d"
mv -- "$original" "$d/file"
mv -- "$d/file" "$destination"
rmdir d