0

i have trouble to use file descriptor

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "line.h"
#include "char.h"

#define DEFAULT_PREFIX "x"
#define DEFAULT_CHUNK_SIZE 1000
#define ALPHABET_SIZE 26
#define MAX_DIGITS 2

void print_usage() {
    printf("Usage: chunk [-l line_count | -w word_count | -c character_count] [-p prefix] [-s suffix] [-f filename.txt | < filename.txt]\n");
}

int main(int argc, char *argv[]) {
    char *prefix = DEFAULT_PREFIX;
    int chunk_size = DEFAULT_CHUNK_SIZE;
    int suffix_start = 0;
    char *filename = NULL;

    // Parse command line arguments
    int opt;
    while ((opt = getopt(argc, argv, "l:w:c:p:s:f:")) != -1) {
        switch (opt) {
            case 'l':
                chunk_size = atoi(optarg);
                break;
  
            case 'w':
                chunk_size = atoi(optarg);
  
            case 'c':
                chunk_size = atoi(optarg);
                break;
  
            case 'p':
                prefix = optarg;
                break;
  
            case 's':
                suffix_start = atoi(optarg);
                break;
  
            case 'f':
                filename = optarg;
                break;
  
            default:
                print_usage();
                return 1;
        }
    }

    // Open input file
    int input_fd = STDIN_FILENO;
    if (filename != NULL) {
        input_fd = open(filename, O_RDONLY);
        if (input_fd == -1) {
            printf("Error: could not open file '%s': %s\n", filename, strerror(errno));
            return -1;
        }
    }

chunk_char(input_fd, chunk_size, prefix, suffix_start);
chunk_line(input_fd, chunk_size, prefix, suffix_start);

return 0;
} // close main

this is chunk.c file and command chunk divides a large file (filename.txt) into smaller chunked files.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "line.h"

#define DEFAULT_PREFIX "x"
#define DEFAULT_CHUNK_SIZE 1000
#define ALPHABET_SIZE 26
#define MAX_DIGITS 2

int chunk_line(int input_fd, int chunk_size, char *prefix, int suffix_start){
// Read input file and write output files
    int line_count = 0;
    int chunk_count = 0;
    char suffix[MAX_DIGITS + 1];
    suffix[MAX_DIGITS] = '\0';
    int output_fd = -1;

    while (1) {
        if (line_count == 0) {
            // Close previous output file
            if (output_fd != -1) {
                close(output_fd);
                output_fd = -1;
            }

            // Open new output file (get new filename)
            snprintf(suffix, MAX_DIGITS + 1, "%02d", suffix_start + chunk_count);
            char *filename = malloc(strlen(prefix) + strlen(suffix) + 1);
            strcpy(filename, prefix);
            strcat(filename, suffix);
            
            output_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
            if (output_fd == -1) {
                printf("Error: could not create file '%s': %s\n", filename, strerror(errno));
                return -1;
            }
            free(filename);

            chunk_count++;
        } // close if loop 

        // Read input
        char buffer[chunk_size];
        ssize_t bytes_read = read(input_fd, buffer, chunk_size);
        if (bytes_read == -1) {
            printf("Error: could not read input: %s\n", strerror(errno));
            return -1;
        }
        if (bytes_read == 0) {
            break;
        }
        
        // write output
        ssize_t bytes_written = write(output_fd, buffer, bytes_read);
        if (bytes_written == -1) {
            printf("Error: could not write output : %s\n", strerror(errno));
        return -1;
        }
    
    // Update line count
    for (int i = 0; i < bytes_written; i++) {
        if (buffer[i] == '\n') {
            line_count++;
        }
    }
    // Check if it's time to start a new chunk
    if (line_count >= chunk_size) {
        line_count = 0;
    }
} // close while loop

// Close input and output files
if (input_fd != STDIN_FILENO) {
    close(input_fd);
}
if (output_fd != -1) {
    close(output_fd);
}

return line_count;
}

this is the chunk_line.c which is in #include "line.h" .

chunk_char code in #include "char.h" is almost same code with chunk_line. (so I'll just pass it because questions gonna so long if I put that also)

but the problem is when I run the chunk.c code,

I got an error and it said 'Error: could not read input: Bad file descriptor '.

i don't know what the problem is. should I move Open input file part to each line.c and char.c file?

springbook
  • 21
  • 2
  • 1) You did not post `chunk_char()` because "is almost same code with chunk_line". When you run your code with `chunk_char(input_fd, chunk_size, prefix, suffix_start);` commented out, do you still get the same problem? 2) Post input used. – chux - Reinstate Monica Mar 24 '23 at 10:09

1 Answers1

1

Key issue: Closed file descriptor

OP has "chunk_char code ... is almost same code with chunk_line."

Given that, chunk_char(input_fd, chunk_size, prefix, suffix_start); can call close(input_fd); and then chunk_line(input_fd, chunk_size, prefix, suffix_start); uses a input_fd to a closed file.

Consider calling close(input_fd) at the same level of code as input_fd = open(filename, O_RDONLY): in main().

Unused open

Code does the if (line_count == 0) test before the // Read input part. Makes more sense to do so after successfully reading data - as suggested here.


Minor: Avoid Schlemiel the Painter's Algorithm

        //char *filename = malloc(strlen(prefix) + strlen(suffix) + 1);
        //strcpy(filename, prefix);
        //strcat(filename, suffix);

        size_t prefix_len = strlen(prefix);
        char *filename = malloc(prefix_len + strlen(suffix) + 1);
        assert(filename); // Consider some error checking
        strcpy(filename, prefix);
        // strcpy instead of strcat
        strcpy(filename + prefix_len, suffix);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256