Search code examples
ciolinked-listsystem-calls

C Stack Manager Project: file I/O with syscalls problems


I'm currently working on a c library that emulates a stack(using a linked list).

The stack has to be able to manage any data Type.

It also has to be able to write it's contents to a file and then retrieve them. Here is where I'm having problems. When I compare the original stack to the one I stored in the file data is not the same.

Here is the code:

writeRead.c

#include <stdio.h>

#include "stack.h"

#define NODES 3

struct my_data {
    int val;
    char name[60];
};

int main() {
    struct my_stack *s1, *fs1;
    struct my_data *data, *data1, *data2;

    // Initialize Stack
    s1 = my_stack_init(sizeof(struct my_data));
    // Initialize data and push to stack
    for (int i = 0; i < NODES; i++) {
        data = malloc(sizeof(struct my_data)); // We must allocate static memory
        data->val = i;
        sprintf(data->name, "Value %d", i);
        if (my_stack_push(s1, data)) {
            puts("Error in my_stack_push()");
            exit(1);
        }
        printf("New node in s1: (%d, %s)\n", data->val, data->name);
    }

    // Write Stack to file
    if (my_stack_write(s1, "/tmp/my_stack.data") == -1) {
        puts("Error in my_stack_write (s1)");
        exit(1);
    }

    // Read Stack from file
    fs1 = my_stack_read("/tmp/my_stack.data");
    if (!fs1) {
        puts("Error in my_stack_read (fs1)");
        exit(1);
    }


    // Compare data of stack s1 (memory) and fs1 (file)
    while ((data1 = my_stack_pop(s1))) {
        printf("FS1 len. %d\n",my_stack_len(fs1));
        data2 = my_stack_pop(fs1);
        printf("Node of s1: (%d, %s)\t", data1->val, data1->name);
        printf("Node of fs1: (%d, %s)\n", data2->val, data2->name);
        if (!data2 || data1->val != data2->val || my_strcmp(data1->name, data2->name)) {
            printf("Data in s1 and fs1 are not the same.\n (data1->val: %d <> data2->val: %d) o (data1->name: %s <> data2->name: "
                   "%s)\n",
                   data1->val, data2->val, data1->name, data2->name);
            exit(1);
        }
    }

    return 0;


}

stack.h

#include <fcntl.h>     /* Modos de apertura de función open()*/
#include <stdlib.h>    /* Funciones malloc(), free(), y valor NULL */
#include <sys/stat.h>  /* Permisos función open() */
#include <sys/types.h> /* Definiciones de tipos de datos como size_t*/
#include <unistd.h>    /* Funciones read(), write(), close()*/

struct my_stack_node {
    void *data;
    struct my_stack_node *next;
};

struct my_stack {
    int size;
    struct my_stack_node *first;
};

int my_strcmp(const char *str1, const char *str2);
struct my_stack *my_stack_init(int size);
int my_stack_push(struct my_stack *stack, void *data);
void *my_stack_pop(struct my_stack *stack);
int my_stack_len(struct my_stack *stack);
struct my_stack *my_stack_read(char *filename);
int my_stack_write(struct my_stack *stack, char *filename);
int my_stack_purge(struct my_stack *stack);

stack.c

#include <stdio.h>
#include "stack.h"

int my_strcmp(const char *str1, const char *str2) {
    int restultatCmp = *str1++ - *str2++;
    //printf("ResultatCmp : %d \n", restultatCmp);
    while(*str1++ && *str2++ && restultatCmp == 0) {
        restultatCmp = *str1 - *str2;
    }
    return restultatCmp;
}

struct my_stack *my_stack_init(int dataSize) {
    struct my_stack *stack = malloc(sizeof(struct my_stack));
    stack -> first = NULL;
    stack -> size = dataSize;
    return stack;
}

int my_stack_push(struct my_stack *stack, void *dataIn) {
    struct my_stack_node *nodeToPush;
    nodeToPush = malloc(sizeof(struct my_stack_node));

    if(stack == NULL && sizeof(dataIn)> 0){
        printf("Null Stack or data size error.\n");
        //la pila debe existir
        return -1;
    } 
    else {
        nodeToPush -> data = dataIn;
        if(stack -> first == NULL) {
            nodeToPush -> next = NULL;
            stack -> first = nodeToPush;

        }
        else {
            nodeToPush -> next = stack -> first;
            stack -> first = nodeToPush;  
        }
    }
    return 0;
}

void *my_stack_pop(struct my_stack *stack) {
    if(stack -> first == NULL) {
        return NULL;
    }
    struct my_stack_node *nodeToDelete = stack -> first;
    void *data = nodeToDelete -> data;
    stack -> first = nodeToDelete -> next;
    free(nodeToDelete);

    return data; 
}

int my_stack_len(struct my_stack *stack) {
    int numNodes = 0;
    struct my_stack_node *currentElement = stack -> first;
    while(currentElement != NULL) {
        numNodes++;
        currentElement = currentElement ->next;
    }
    return numNodes;
}

void recursiveWrite(struct my_stack_node *nodo, int fileDesc, int sizeData) {
    if(nodo ->next != NULL) recursiveWrite(nodo -> next,fileDesc,sizeData);
    if(write(fileDesc, nodo -> data, sizeData)== -1){
        printf("Error de escritura\n");
        return;// error escritura.
    }
}

int my_stack_write(struct my_stack *stack, char *filename) {
    struct my_stack_node *currentNode = stack -> first;
    int fileDesc = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if(fileDesc == -1) {
        return -1; // Error open();
    }
    if(write(fileDesc, &stack -> size, sizeof(stack -> size)) == -1){
        return -1; // Error write();
    }
    int sizeData = stack -> size;
    recursiveWrite(currentNode,fileDesc,sizeData);
    close(fileDesc);

    return my_stack_len(stack);
}

struct my_stack *my_stack_read(char *filename) {
    int fileDesc = open(filename, O_RDONLY, S_IRUSR);
    if(fileDesc == -1) {
        return NULL; // Error open();
    }
    char *buffer = malloc(sizeof(int));
    int readBytes;
    if((readBytes = read(fileDesc, buffer, sizeof(int))) == -1){
        printf("Error reading data size.\n");
        return NULL;
    }
    int dataSize = 0;
    dataSize = (int) *buffer; // parse data Size from buffer.
    struct my_stack *stack; 
    stack = malloc(sizeof(struct my_stack));
    stack = my_stack_init(dataSize); // initialize Stack
    buffer = realloc(buffer, stack -> size);
    if(buffer == NULL){
        return NULL;
    }
    else{
        while(read(fileDesc, buffer, stack -> size) > 0) {
            if((my_stack_push(stack,buffer))== -1){
                printf("Error en my_stack_read: Push error.\n");
                return NULL;
            }

        }
    close(fileDesc);
    return stack;
    }   
}

Sorry for the large code I tried to simplify the example as much as I could.

Output:

New node in s1: (0, Value 0)
New node in s1: (1, Value 1)
New node in s1: (2, Value 2)
FS1 len. 3
Node of s1: (2, Value 2)        Node of fs1: (2, Value 2)
FS1 len. 2
Node of s1: (1, Value 1)        Node of fs1: (2, Value 2)
Data in s1 and fs1 are not the same.
 (data1->val: 1 <> data2->val: 2) o (data1->name: Value 1 <> data2->name: Value 2)

Expected output:

New node in s1: (0, Value 0)
New node in s1: (1, Value 1)
New node in s1: (2, Value 2)
FS1 len. 3
Node of s1: (2, Value 2)        Node of fs1: (2, Value 2)
FS1 len. 2
Node of s1: (1, Value 1)        Node of fs1: (1, Value 1)
FS1 len. 1
Node of s1: (0, Value 0)        Node of fs1: (0, Value 0)

I'm almost sure that the file writting is correct. Checked with a hex editor and should be correct.

So my guesses are that my fault is at the reading of the file.

Forgot to mention that a restriction of the project is that system calls for I/O are mandatory.

Any help would be very much appreciated.

Thanks in advance.

Edit1:

Changed *my_stack_read() as @AndrewHenle suggested, the output is still not the expected.

struct my_stack *my_stack_read(char *filename) {
    int fileDesc = open(filename, O_RDONLY, S_IRUSR);
    if(fileDesc == -1) {
        return NULL; // Error open();
    }
    char *buffer = malloc(sizeof(int));
    ssize_t readBytes;
    readBytes = read(fileDesc, buffer, sizeof(int));
    if(readBytes == -1) {
        return NULL;
    }
    int dataSize = 0;
    dataSize = (int) *buffer; // parse data Size from buffer.
    struct my_stack *stack; 
    stack = malloc(sizeof(struct my_stack));
    stack = my_stack_init(dataSize); // initialize Stack
    buffer = realloc(buffer, stack -> size);
    if(buffer == NULL){
        return NULL;
    }
    else{
        while(read(fileDesc, buffer, stack -> size) > 0) {
            int push = my_stack_push(stack,buffer);
            if(push == -1){
                printf("Error en my_stack_read: Push error.\n");
                return NULL;
            }

        }
    close(fileDesc);
    return stack;
    }   

Solution

  • Solution:

    I found my error in *my_stack_read:

    while(read(fileDesc, buffer, stack -> size) > 0) {
            int push = my_stack_push(stack,buffer);
            if(push == -1){
                printf("Error en my_stack_read: Push error.\n");
                return NULL;
            }
            buffer = malloc(stack -> size);
        }
    

    buffer = malloc(stack -> size); I had allocated the memory outside the for loop, and I didn't allocate for the subsequent reads.

    I thought the read would use same direction overwritting it's content but it seems this is not possible.

    Could anyone explain the reason?

    Thank you all.