I have a program that should copy files from one folder to another. But the function that reads the files is being blocked when the file have 0 bytes. When I do CTRL+C de program continues and copies all the remaining files which are not 0 bytes. In main.c I have a simple fork to call read and write function according to parent and child processes. All files are correctly copied but it always stops when file is 0 bytes. The read function is:
int read_file(char *ficheiro) {
FILE *fp = fopen(ficheiro, "rb");
if (fp == NULL) {
exit_on_error(-1, "fopen falhou");
}
MSG_STRUCT msg;
int total_bytes = 0, bytes_lidos;
while ((bytes_lidos = fread(msg.buffer, 1, TAMANHO_BUFFER, fp)) > 0) {
msg.type = 1;
msg.bytes_lidos = bytes_lidos;
if (msgsnd(msg_id, &msg, sizeof(MSG_STRUCT) - sizeof(long), 0) == -1) {
perror("Erro ao enviar mensagem");
fclose(fp);
exit(1);
}
total_bytes += bytes_lidos;
}
// Enviar mensagem de finalização, fora do loop
msg.bytes_lidos = 0;
if (msgsnd(msg_id, &msg, sizeof(MSG_STRUCT) - sizeof(long), 0) == -1) {
perror("Erro ao enviar mensagem de finalização");
fclose(fp);
exit(1);
}
fclose(fp);
return total_bytes;
}
And the write function is:
int write_file(char *ficheiro) {
FILE *fp = fopen(ficheiro, "wb");
if (fp == NULL) {
exit_on_error(-1, "fopen falhou");
}
MSG_STRUCT msg;
int total_bytes = 0;
while (1) {
if (msgrcv(msg_id, &msg, sizeof(MSG_STRUCT) - sizeof(long), 1, 0) == -1) {
perror("Erro ao receber mensagem");
fclose(fp);
exit(1);
}
if (msg.bytes_lidos == 0) {
printf("msg.bytes == 0\n");
break;
}
fwrite(msg.buffer, 1, msg.bytes_lidos, fp);
total_bytes += msg.bytes_lidos;
}
fclose(fp);
return total_bytes;
}
In main I have:
int main(int argc, char **argv) {
if (argc < 3) {
fprintf(stderr, "Número de argumentos inválido\n");
fprintf(stderr, "Sintaxe: %s <origem> <destino>\n", argv[0]);
exit(-1);
}
msg_id = cria_msg(MSG_KEY);
int status;
if (fork() != 0) {
read_file(argv[1]);
wait(&status);
} else {
write_file(argv[2]);
exit(0);
}
remove_msg(MSG_KEY);
return 0;
}
I expect all files to be copied from one folder to another, even if the file is empty.
The Bash file is
#!/bin/bash
CP_CMD=cp-msg
TESTE_DIR=teste
OUTPUT_DIR=output
if [ $# == 2 ]
then
TESTE_DIR=$1
OUTPUT_DIR=$2
fi
if [ ! -d $TESTE_DIR ]
then
echo "Não existe pasta $TESTE_DIR"
exit 1
fi
if [ ! -d $OUTPUT_DIR ]
then
echo "Criar pasta $OUTPUT_DIR"
mkdir $OUTPUT_DIR
fi
rm -f $OUTPUT_DIR/*
for ficheiro in $TESTE_DIR/*
do
nome=`basename $ficheiro`
tamanho_ficheiro=$(stat -c%s "$ficheiro")
echo -n "Copiar $ficheiro ($tamanho_ficheiro bytes) para $OUTPUT_DIR/$nome: "
/usr/bin/time -f "em %E" ./$CP_CMD $ficheiro $OUTPUT_DIR/$nome
echo -n "Verificar cópia: "
diff $ficheiro $OUTPUT_DIR/$nome >/dev/null
if [ $? != 0 ]
then
echo "ficheiros diferentes"
else
echo "ficheiros iguais"
fi
echo
done
It is highly unlikely that that is happening. More likely, it is the receiver's
msgrcv()call that blocks.Note well that for a zero-byte file, the very first
fread()call inread_file()will return 0, and therefore the body of thewhileloop will not be executed even once. Only in that loop body ismsg.typeever set, so whenread_file()sends its end-of-file message, the message type is still indeterminate.But the receiver requests messages of type 1 (only), so it is unreasonable to expect that it will dequeue the reader's end-of-file message in this case (that message's type most likely being different from 1).
Simple solutions:
in
read_file(), lift the assignmentmsg.type = 1;out of the loop and before.OR
in
write_file(), in themsgrcv()call, specify message type 0, so as to always receive the next message regardless of type.Or both.