Files

204 lines
5.2 KiB
C

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ufs.h"
void usage() {
fprintf(stderr, "usage: mkfs -f <image_file> [-d <num_data_blocks] [-i <num_inodes>]\n");
exit(1);
}
int main(int argc, char *argv[]) {
int ch;
char *image_file = NULL;
int num_inodes = 32;
int num_data = 32;
int visual = 0;
while ((ch = getopt(argc, argv, "i:d:f:v")) != -1) {
switch (ch) {
case 'i':
num_inodes = atoi(optarg);
break;
case 'd':
num_data = atoi(optarg);
break;
case 'f':
image_file = optarg;
break;
case 'v':
visual = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (image_file == NULL)
usage();
unsigned char *empty_buffer;
empty_buffer = calloc(UFS_BLOCK_SIZE, 1);
if (empty_buffer == NULL) {
perror("calloc");
exit(1);
}
int fd = open(image_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
perror("open");
exit(1);
}
assert(num_inodes >= 32);
assert(num_data >= 32);
// presumed: block 0 is the super block
super_t s;
// totals
s.num_inodes = num_inodes;
s.num_data = num_data;
// inode bitmap
int bits_per_block = (8 * UFS_BLOCK_SIZE); // remember, there are 8 bits per byte
s.inode_bitmap_addr = 1;
s.inode_bitmap_len = num_inodes / bits_per_block;
if (num_inodes % bits_per_block != 0)
s.inode_bitmap_len++;
// data bitmap
s.data_bitmap_addr = s.inode_bitmap_addr + s.inode_bitmap_len;
s.data_bitmap_len = num_data / bits_per_block;
if (num_data % bits_per_block != 0)
s.data_bitmap_len++;
// inode table
s.inode_region_addr = s.data_bitmap_addr + s.data_bitmap_len;
int total_inode_bytes = num_inodes * sizeof(inode_t);
s.inode_region_len = total_inode_bytes / UFS_BLOCK_SIZE;
if (total_inode_bytes % UFS_BLOCK_SIZE != 0)
s.inode_region_len++;
// data blocks
s.data_region_addr = s.inode_region_addr + s.inode_region_len;
s.data_region_len = num_data;
int total_blocks = 1 + s.inode_bitmap_len + s.data_bitmap_len + s.inode_region_len + s.data_region_len;
// super block is the first block
int rc = pwrite(fd, &s, sizeof(super_t), 0);
if (rc != sizeof(super_t)) {
perror("write");
exit(1);
}
printf("total blocks %d\n", total_blocks);
printf(" inodes %d [size of each: %lu]\n", num_inodes, sizeof(inode_t));
printf(" data blocks %d\n", num_data);
printf("layout details\n");
printf(" inode bitmap address/len %d [%d]\n", s.inode_bitmap_addr, s.inode_bitmap_len);
printf(" data bitmap address/len %d [%d]\n", s.data_bitmap_addr, s.data_bitmap_len);
// first, zero out all the blocks
int i;
for (i = 1; i < total_blocks; i++) {
rc = pwrite(fd, empty_buffer, UFS_BLOCK_SIZE, i * UFS_BLOCK_SIZE);
if (rc != UFS_BLOCK_SIZE) {
perror("write");
exit(1);
}
}
//
// need to allocate first inode in inode bitmap
//
typedef struct {
unsigned int bits[UFS_BLOCK_SIZE / sizeof(unsigned int)];
} bitmap_t;
assert(sizeof(bitmap_t) == UFS_BLOCK_SIZE);
bitmap_t b;
for (i = 0; i < 1024; i++)
b.bits[i] = 0;
b.bits[0] = 0x1 << 31; // first entry is allocated
rc = pwrite(fd, &b, UFS_BLOCK_SIZE, s.inode_bitmap_addr * UFS_BLOCK_SIZE);
assert(rc == UFS_BLOCK_SIZE);
//
// need to allocate first data block in data bitmap
// (can just reuse this to write out data bitmap too)
//
rc = pwrite(fd, &b, UFS_BLOCK_SIZE, s.data_bitmap_addr * UFS_BLOCK_SIZE);
assert(rc == UFS_BLOCK_SIZE);
//
// need to write out inode
//
typedef struct {
inode_t inodes[UFS_BLOCK_SIZE / sizeof(inode_t)];
} inode_block;
inode_block itable;
itable.inodes[0].type = UFS_DIRECTORY;
itable.inodes[0].size = 2 * sizeof(dir_ent_t); // in bytes
itable.inodes[0].direct[0] = s.data_region_addr;
for (i = 1; i < DIRECT_PTRS; i++)
itable.inodes[0].direct[i] = -1;
rc = pwrite(fd, &itable, UFS_BLOCK_SIZE, s.inode_region_addr * UFS_BLOCK_SIZE);
assert(rc == UFS_BLOCK_SIZE);
//
// need to write out root directory contents to first data block
// create a root directory, with nothing in it
//
typedef struct {
dir_ent_t entries[128];
} dir_block_t;
// xxx assumes 4096 block, 32 byte entries
assert(sizeof(dir_ent_t) * 128 == UFS_BLOCK_SIZE);
dir_block_t parent;
strcpy(parent.entries[0].name, ".");
parent.entries[0].inum = 0;
strcpy(parent.entries[1].name, "..");
parent.entries[1].inum = 0;
for (i = 2; i < 128; i++)
parent.entries[i].inum = -1;
rc = pwrite(fd, &parent, UFS_BLOCK_SIZE, s.data_region_addr * UFS_BLOCK_SIZE);
assert(rc == UFS_BLOCK_SIZE);
if (visual) {
int i;
printf("\nVisualization of layout\n\n");
printf("S");
for (i = 0; i < s.inode_bitmap_len; i++)
printf("i");
for (i = 0; i < s.data_bitmap_len; i++)
printf("d");
for (i = 0; i < s.inode_region_len; i++)
printf("I");
for (i = 0; i < s.data_region_len; i++)
printf("D");
printf("\n\n");
}
(void) fsync(fd);
(void) close(fd);
return 0;
}