2017-04-22 4 views
0

Ich versuche read zu verwenden, um von stdin zu lesen und die gelesenen Bytes an stdout zu senden und die Dateien, die als Argumente übergeben werden (die tee Befehl imitieren). Allerdings, wenn ich ausführen:C lesen Funktion lesen mehr Bytes als angefordert

echo AAAAAAAAAA | ./tee -a file 

ich

AAAAAAAAAA 
Â7þ­hý6þ­hý¥g¢c¾ 
@ERROR: failed to write whole buffer (140726359686392 != 2880) 

Sie können sehen, dass read eine Zahl zurückgibt, die viel größer als die angeforderte Puffergröße ist. write schreibt auch mehr als angefordert, aber während die von read zurückgegebene Zahl mit jeder Ausführung variiert, gibt writes immer 2880 zurück, unabhängig von der Größe der Eingabe. Hier

ist der Code:

#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 

#include <fcntl.h> 
#include <stdarg.h> 
#include <sys/stat.h> 
#include <unistd.h> 

#include <string.h> 

#define BUFFER_SIZE 64 

extern int optind; 

void exit_err(char *format, ...) 
{ 
    va_list args; 

    fflush(stdout); 

    va_start(args, format); 
    fprintf(stderr, format, args); 
    va_end(args); 

    fprintf(stderr, "\n"); 

    fflush(stderr); 
    exit(EXIT_FAILURE); 
} 

int main(int argc, char *argv[]) 
{ 
    if (argc < 2 || strncmp(argv[1], "--help", 6) == 0) 
     exit_err("USAGE: %s [-a] [OUTPUTFILE]", argv[0]); 

    bool append = false; 

    char opt; 
    while ((opt = getopt(argc, argv, "a")) != -1) { 
     switch (opt) 
     { 
      case 'a': 
       append = true; 
       break; 
      default: /* ? */ 
       exit_err("USAGE: %s [-a] [OUTPUTFILE]", argv[0]); 
     } 
    } 

    if (optind >= argc) { 
     exit_err("ERROR: expected argument after options"); 
     exit(EXIT_FAILURE); 
    } 

    int open_flags = O_WRONLY | O_CREAT; 
    if (append) 
     open_flags |= O_APPEND; 
    else 
     open_flags |= O_TRUNC; 

    mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP; 

    int num_output_files = argc - optind + 1; 
    int output_fd[num_output_files]; 
    output_fd[0] = STDOUT_FILENO; 

    int i; 
    for (i = 1; i < num_output_files; ++i, ++optind) { 
     output_fd[i] = open(argv[optind], open_flags, permissions); 
     if (output_fd[i] == -1) 
      exit_err("ERROR: failed to open %s", argv[optind]); 
    } 

    ssize_t num_read, num_written; 
    char buffer[BUFFER_SIZE]; 
    while ((num_read = read(STDIN_FILENO, buffer, BUFFER_SIZE)) > 0) 
     for (i = 0; i < num_output_files; ++i) 
      if ((num_written = write(output_fd[i], buffer, BUFFER_SIZE)) != num_read) 
       exit_err("ERROR: failed to write whole buffer (%zd != %zd)", num_read, num_written); 

    if (num_read == -1) 
     exit_err("ERROR: failed to read from stdin"); 

    for (i = 0; i < num_output_files; ++i) 
     if (close(output_fd[i]) == -1) 
      exit_err("ERROR: failed to close file"); 

    exit(EXIT_SUCCESS); 
} 

Antwort

2

Da Sie wrting BUFFER_SIZE Bytes, wenn Sie num_read lesen.

Just do it wie diese

while ((num_read = read(STDIN_FILENO, buffer, BUFFER_SIZE)) > 0) { 
    for (i = 0; i < num_output_files; ++i) { 
     if ((num_written = write(output_fd[i], buffer, num_read)) != num_read) { 
      exit_err("ERROR: failed to write whole buffer (%zd != %zd)", num_read, num_written); 
     } 
    } 
} 

Auch Gebrauch Klammern und vermeiden, dass zu viele Ebenen der Vertiefung, in diesem Fall war es schwer zu lesen.

+0

Aaaaaaaaaaarg, wie könnte ich das nicht sehen ... –

0

Neben dem Schreiben der falschen Größe ist Ihre Fehlermeldung Müll, weil Sie eine va_list an fprintf übergeben, die es nicht erwartet. Sie müssen stattdessen vfprintf dort anrufen.