1

This is a snippet of the LIST ftp's cmd:

count = file_list("./", &files);
if((fp_list = fopen("listfiles.txt", "w")) == NULL){
  perror("Impossibile aprire il file per la scrittura LIST");
  onexit(newsockd, sockd, 0, 2);
}
for(i=0; i < count; i++){
  if(strcmp(files[i], "DIR ..") == 0 || strcmp(files[i], "DIR .") == 0) continue;
  else{
    fprintf(fp_list, "%s\n", files[i]);
  }
}
fclose(fp_list);
if((fpl = open("listfiles.txt", O_RDONLY)) < 0){
  perror("open file with open");
  onexit(newsockd, sockd, 0, 2);
  exit(1);
}
if(fstat(fpl, &fileStat) < 0){
  perror("Errore fstat");
  onexit(newsockd, sockd, fpl, 3);
}
fsize = fileStat.st_size;
if(send(newsockd, &fsize, sizeof(fsize), 0) < 0){
  perror("Errore durante l'invio grande file list");
  onexit(newsockd, sockd, fpl, 3);
}
rc_list = sendfile(newsockd, fpl, &offset_list, fileStat.st_size);
if(rc_list == -1){
  perror("Invio file list non riuscito");
  onexit(newsockd, sockd, fpl, 3);
}
if((uint32_t)rc_list != fsize){
  fprintf(stderr, "Error: transfer incomplete: %d di %d bytes inviati\n", rc_list, (int)fileStat.st_size);
  onexit(newsockd, sockd, fpl, 3);
}
printf("OK\n");
close(fpl);
if(remove( "listfiles.txt" ) == -1 ){
  perror("errore cancellazione file");
  onexit(newsockd, sockd, 0, 2);
}

wher &files is declared as char **files and the function list_files is a function written by me that isn't relevant for my problem.
My problem: the first time LIST cmd it's called it works properly but if i call LIST another time it always give me "error, transfer incomplete" i don't understand why...

polslinux
  • 1,739
  • 9
  • 34
  • 73
  • 1
    Is the "error, transfer incomplete" message seen from the code you posted in your question? When in that case? Otherwise, what does the code in the question report? – Some programmer dude Aug 08 '12 at 08:02
  • yes, it is what i've posted into the question :) it give me an error when the sendfile function doesn't send all the file... – polslinux Aug 08 '12 at 08:38
  • What is `offset_list` and how do you initialize it? Remember that if `sendfile` can't send everything then it will return a value _less than_ the requested size, and you will have to adjust the size and try again. – Some programmer dude Aug 08 '12 at 08:45
  • offset_list is initialized with `offset_t`...so i have to do this? `send: if((uint32_t)rc_list != fsize){ fprintf(stderr, "Error: transfer incomplete: %d di %d bytes inviati\n", rc_list, (int)fileStat.st_size); goto send; }` – polslinux Aug 08 '12 at 08:51

2 Answers2

7

The sendfile function may not send all data in one call, in which case it will return a number less than requested. You treat this as an error, but instead you should try again. One way is to use a loop similar to this:

// Offset into buffer, this is where sendfile starts reading the buffer
off_t offset = 0;

// Loop while there's still some data to send
for (size_t size_to_send = fsize; size_to_send > 0; )
{
    ssize_t sent = sendfile(newsockd, fpl, &offset, size_to_send);

    if (sent <= 0)
    {
        // Error or end of file
        if (sent != 0)
            perror("sendfile");  // Was an error, report it
        break;
    }

    size_to_send -= sent;  // Decrease the length to send by the amount actually sent
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

I've found my problem.
When i call sendfile multiple times the variable off_t offset_list; remains "dirty".
If a call sendfile the 1st time offest_list will have a value that won't be deleted the 2nd time i call that function.
So if i have to write offset_list = 0; before rc_list = sendfile(newsockd, fpl, &offset_list, fileStat.st_size); and all work!

polslinux
  • 1,739
  • 9
  • 34
  • 73
  • it also fixed my problem!!! and I was into it for entire days !!! I can't say how much I'm happy right now. THANKS – UrbiJr Jan 15 '17 at 16:16