cstructsegmentation-faultfilesystemsfwrite

fwrite causes segmentation fault


please point out the mistake I could have made. I am trying to implement a simple file system based on the guide provided here. I have decided to implement the file system interface as read and writes to a file. The code still needs refactoring but here is the code:

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


#define TOTAL_FILE_SIZE 4227104
#define TOTAL_DIR_ENTRIES 1024
#define NUM_FAT_ENTRIES 8192

typedef struct super_block {
    unsigned short total_sectors;           /* max value 8192 */
    unsigned short bytes_per_sector;        /* max value 512 */
    unsigned short available_sectors;       /* max value 8192 */
    unsigned short total_dir_entries;       /* fixing it to 1024 */
    unsigned short available_dir_entries;   /* max value 1024 */
    unsigned char  label[8];                /* label for the filesystem */

    /* These are not used */
    unsigned short sectors_per_cluster;     /* We always set it to 1*/
    unsigned char  reserved[12];            /* Just making it 32 bytes */
} super_block;

/* Each dir entry is 16 bytes */
typedef struct dir_entry {
    unsigned char  file_name[10];
    unsigned short fat_entry;
    unsigned int   size;
} dir_entry;

/* Each FAT entry is 2 bytes; times 8192 entries => 16 KiB
 * size of data block (sector) can be varied
 * number of dir_entries can be varied
 * the number of fat entries is same as the number of data blocks
 * the number of data blocks can be varied total_sectors
 *
 * the total size of our filesystem is => +
 * size of super block = 32 bytes
 * size of dir entry = 16 KiB
 * size of fat = 16 KiB
 * total size of data block = 8192 * 512 bytes => 4 MiB
 * Total bytes = 4227104
 * End: sFAT.c
*/

/* mkfs.c
 *
*/

/* Later: integrate label of FS to argument */
void mkfs(const char *filename) {
    /* Write super block, dir entries and fat table and data blocks to the file */
    super_block sb = {
            .total_sectors = 8192,
            .bytes_per_sector = 512,
            .available_sectors = 512,
            .total_dir_entries = 1024,
            .available_dir_entries = 1024,
            .sectors_per_cluster = 1,
            .label = "Demo FS",
            .reserved = ""
    };

    dir_entry default_dir_entry = {
            .file_name = "",
            .fat_entry = 0,
            .size = 0,
    };

    unsigned short default_fat_entry = 0;

    /* Write sb, 1024 dir_entry and 8192 default_fat_entry and 4 MiB data to create our filesystem */
    FILE *f = fopen(filename, "wb");
    if (f == NULL) {
        fprintf(stderr, "Error opening file: %s\n", filename);
    }

    /* Write super block */
    /* I seem to encounter SEGMENTATION FAULT in this line */
    fwrite(&sb, sizeof (super_block), 1, f);
    /* Write dir entries */
    fwrite(&default_dir_entry, sizeof(dir_entry), TOTAL_DIR_ENTRIES, f);
    fwrite(&default_fat_entry, sizeof(unsigned short), NUM_FAT_ENTRIES, f);
    char *data;

    data = malloc(TOTAL_FILE_SIZE - ftell(f));
    fwrite(data, TOTAL_FILE_SIZE - ftell(f), 1, f);
    free(data);
    fclose(f);
    fprintf(stdout, "Filesystem created successfully!\n");
}
/* End: mkfs.c */

/* main.c
 *
*/

void display_help(char *program_name) {
    fprintf(stdout, "Usage: %s [function name]\n", program_name);
    fprintf(stdout, "Functions:\n");
    fprintf(stdout,"  mkfs\n");
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        display_help(argv[0]);
        return 1;
    }
    if (strcmp(argv[1], "mkfs") == 0) {
        mkfs(argv[2]);
    }
    else {
        display_help(argv[0]);
        return 1;
    }
    return 0;
}

/*
 *
 * End: main.c
 */

I encounter segmentation fault on the fwrite statment of the super block structure. However, if I comment out that line, the file runs successfully. What mistake could I have possibly made?


Solution

  • I had misunderstood the documentation of fwrite. The error was due to:

    fwrite, when supplied with nitems argument, will write contents from ptr upto nitems times taking the size to be the size.

    fwrite(&default_dir_entry, sizeof(dir_entry), TOTAL_DIR_ENTRIES, f);
    

    The code is working now.