lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAFf+5zjSkGyMXTybY7wioFM9gxruhGfKNKh797vvy29NMWsa4g@mail.gmail.com>
Date:   Mon, 16 Jan 2023 17:18:29 +0530
From:   Amit <amitchoudhary0523@...il.com>
To:     linux-kernel@...r.kernel.org
Subject: Alternate implementation of getline() function of standard C library.

Alternate implementation of getline() function of standard C library.

---- Start of Code ----

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define NO_ERROR 0 // no error happened.
#define INVALID_FD -1 // fd is less than 0.
#define NO_MEMORY -2 // memory not available.
#define FILE_LSEEK_ERROR -3 // error in seeking file

#define BUF_SIZE_INCREMENT 1024

#define NEW_LINE '\n'

char *get_line_from_file(int fd, int *error_num);

/*
 * char *get_line_from_file(int fd, int *error_num):
 *
 * Function get_line_from_file() returns a line from the file represented by fd.
 *
 * This function supports regular files only (and not pipes, sockets, etc).
 *
 * If fd is less than 0 then NULL is returned and *error_num is assigned the
 * appropriate error value (INVALID_FD in this case).
 *
 * In case of any error, *error_num is assigned the appropriate error value.
 *
 * The high level algorithm of this function is:
 *
 *      The function get_line_from_file() reads some bytes in a buffer from the
 *      file and tries to find newline in the buffer. If a newline is not found
 *      then it reads more bytes from the file in the buffer. When a newline is
 *      found in the buffer, then the newline is replaced with null byte and the
 *      buffer is reallocated to correct size. Then the file offset for reading
 *      is set to the start of the next line. And then the buffer is returned to
 *      the user.
 *
 * Please note that the returned line/buffer doesn't contain any newlines.
 *
 * The line/buffer returned by this function is allocated using realloc(),
 * so it is user's responsibility to free the line (free memory).
 *
 */
char *get_line_from_file(int fd, int *error_num)
{

    char *buf = NULL;
    char *buf_temp = NULL;

    long curr_buf_size = 0;
    long curr_data_len = 0;

    ssize_t bytes_read = -1;
    int end_of_file_reached_or_error = 0;
    int new_line_found = 0;
    long i = 0;

    *error_num = NO_ERROR;

    if (fd < 0) {
        *error_num = INVALID_FD;
        return NULL;
    }

    while (1) {

        buf_temp = realloc(buf, (size_t)(curr_buf_size + BUF_SIZE_INCREMENT));
        if(!buf_temp) {
            *error_num = NO_MEMORY;
            free(buf);
            return NULL;
        }
        buf = buf_temp;
        curr_buf_size = curr_buf_size + BUF_SIZE_INCREMENT;

        // read data from file
        while (curr_data_len != curr_buf_size) {

            bytes_read = read(fd, buf + curr_data_len,
                              (size_t)(curr_buf_size - curr_data_len));

            if (bytes_read == 0) { // end of file reached
                // Check if no bytes were read earlier also in this call to
                // get_line_from_file(). If yes, then this means that end of
                // test file was reached (but not actually read) in the last
                // call to get_line_from_file(). So, this time end of file was
                // read and 0 was returned by read. So, since there are no bytes
                // to process, free the buffer and return NULL.
                if (curr_data_len == 0) {
                    free(buf);
                    return NULL;
                }
            } // end of if bytes_read == 0

            if (bytes_read <= 0) {
                end_of_file_reached_or_error = 1;
                break;
            } // end of if bytes_read <= 0

            curr_data_len = curr_data_len + bytes_read;

        } // end of inner while (1)

        new_line_found = 0;

        for (i = 0; i < curr_data_len; i++) {
            if (buf[i] == NEW_LINE) {
                buf[i] = 0;
                new_line_found = 1;
                break;
            }
        } // end of for loop

        if (new_line_found) {

            // realloc and seek
            buf_temp = realloc(buf, (size_t)(i + 1));
            if(!buf_temp) {
                *error_num = NO_MEMORY;
                free(buf);
                return NULL;
            }

            if (lseek(fd, (i + 1) - curr_data_len, SEEK_CUR) < 0) {
                *error_num = FILE_LSEEK_ERROR;
                free(buf);
                return NULL;
            }
            return buf_temp;

        } else { // new line not found

            // NEW_LINE not found and end of file has been reached or some
            // error happened. So, allocate one extra byte for terminating
            // null byte and return.
            if (end_of_file_reached_or_error) {

                buf_temp = realloc(buf, (size_t)(curr_data_len + 1));
                if(!buf_temp) {
                    *error_num = NO_MEMORY;
                    free(buf);
                    return NULL;
                }
                buf_temp[curr_data_len] = 0;
                return buf_temp;

            } // end of if end_of_file_reached_or_error

        } // end of if - else (new_line_found)

    } // end of outer while (1)

} // end of get_line_from_file

static void print_usage_and_exit(void)
{

    printf("\n");
    printf("Usage: get_line_from_file test_file_name\n");
    printf("\n");
    exit(1);

} // print_usage_and_exit

int main(int argc, char * argv[])
{

    int fd = -1;
    char *line = NULL;
    int error_num = 0;

    if (argc != 2) {
        printf("\nOnly two arguments are required."
               " Program name and test file name.\n");
        print_usage_and_exit();
    }

    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        printf("\n%s: File \"%s\" could not be opened. Exiting..\n\n",
               __FILE__, argv[1]);
        exit(1);
    }

    while ((line = get_line_from_file(fd, &error_num)) != NULL) {
        printf("%s\n", line);
        free(line);
    }

    if (error_num != 0) {
        printf("\nError number returned = %d\n\n", error_num);
    }

    close(fd);

} // end of main

---- End of Code ----

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ