Home > Back-end >  fwrite function writing data wrongly
fwrite function writing data wrongly

Time:04-22

I'm writing a program to read a specified piece of data from one file and write it into a specified offset of a second file, but I have a problem. The fwrite function for some reason isn't writing the data read from the first file. Instead, it writes a non-printing character (possibly null character, idk) at the offset of the second file. Here's the code:

int main(int argc, char **args)
{
    if (argc < 7)
    {
        print_usage(args[0]);
        exit(EXIT_FAILURE);
    }
    else if (argc > 7)
    {
        printf("Too many parameters\n");
        
        exit(EXIT_FAILURE);
    }
    
    if (geteuid() != 0)
    {
        printf("This program requires root privileges\n");
        
        exit(EXIT_FAILURE);
    }
    
    unsigned long offset;
    unsigned long size;
    char *partpath;
    char *filepath;
    
    int c;
    
    for (c = 0; c < argc; c  )
    {
        char *arg = args[c];
        
        if (strcmp(arg, "-o") == 0)
        {
            offset = strtoul(args[  c], NULL, 0);
            
            continue;
        }
        
        if (strcmp(arg, "-s") == 0)
        {
            size = strtoul(args[  c], NULL, 0);
            
            continue;
        }
        
        if (c == argc - 2)
            partpath = args[c];
        if (c == argc - 1)
            filepath = args[c];
    }

    printf("offset: %lu (0x%lx)\nsize: %lu (0x%lx)\npartition: %s\nfile: %s\n", offset, offset, size, size, partpath, filepath);
    
    flash_part(partpath, offset, filepath, size);

    return 0;
}

void flash_part(const char *partition_path, unsigned long offset, const char *file_to_flash, unsigned long size)
{
    log("Opening files...");
    FILE *partition = fopen(partition_path, "r ");
    
    FILE *flash_file = fopen(file_to_flash, "r");
    
    log("Jumping to partition offset...");
    // jump to partition offset
    fseek(partition, offset, SEEK_SET);
    
    // start flashing chunk by chunk

    log("Start flashing...");
    void *chk = calloc(1, sizeof(void*));
    size_t count = read_chk(flash_file, chk);
    
    printf("readed %d bytes\n", count);
    
    write_chk(partition, chk,  count);
    free(chk);
    
    while (count >= CHK_SIZE)
    {
        chk = calloc(1, sizeof(void*));
        count = read_chk(flash_file, chk);
        
        write_chk(partition, chk, count);
        
        free(chk);
    }
    
    log("Partition flashed, closing files...");
    
    fclose(partition);
    fclose(flash_file);
}

size_t read_chk(FILE *file, void *out)
{
    char *chk_data = calloc(CHK_SIZE, 1);
    
    size_t readed = fread(chk_data, 1, CHK_SIZE, file);
    
    out = chk_data;

    return readed;
}

void write_chk(FILE *file, void *data, unsigned int size)
{
    fwrite(data, 1, size, file);
}

What's wrong with it?

CodePudding user response:

Your read_chk is completely broken. You accept a pointer from the user, ignore it, allocate a completely different thing, populate that, replace the pointer received (rather than copying data to where it points; assigning to a pointer changes that pointer, and not the copy of the same pointer the caller holds), so from the point of view of the caller, nothing happened; it passed a pointer to a zeroed buffer, you didn't put anything in the buffer, so it's still got the original zeroes (the "caller" might notice eventually when the program crashes from the progressive memory leak from read_chk's calloc calls that are never freed, but that's not useful feedback really).

Essentially, nothing is wrong with your writing, it's accurately writing out all the zeroes you told it to write.

The solution depends on the value of CHK_SIZE; if it's the same as sizeof(void*), then just get rid of chk_data and directly pass out to fread in its place. If it's larger, you do the same thing, but change the caller to calloc using CHK_SIZE instead of sizeof(void*). Either way, read_chk changes to look like:

size_t read_chk(FILE *file, void *out)
{    
    return fread(out, 1, CHK_SIZE, file);
}

leaving it to the caller to provide a CHK_SIZE buffer to use. The caller could skip the calloc entirely too; a stack array of char buf[CHK_SIZE]; could be used and remove the need for dynamic allocation and freeing.

  •  Tags:  
  • c
  • Related