531 lines
15 KiB
C
531 lines
15 KiB
C
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
typedef uint8_t u8;
|
|
typedef uint16_t u16;
|
|
typedef uint32_t u32;
|
|
typedef int16_t i16;
|
|
typedef int32_t i32;
|
|
|
|
|
|
|
|
#define BLOCK_SIZE 1024
|
|
#define BLOCK_OFFSET(i) (i * BLOCK_SIZE)
|
|
#define NUM_BLOCKS 1024
|
|
#define NUM_INODES 128
|
|
|
|
#define LOST_AND_FOUND_INO 11
|
|
#define HELLO_WORLD_INO 12
|
|
#define HELLO_INO 13
|
|
#define LAST_INO HELLO_INO
|
|
|
|
#define SUPERBLOCK_BLOCKNO 1
|
|
#define BLOCK_GROUP_DESCRIPTOR_BLOCKNO 2
|
|
#define BLOCK_BITMAP_BLOCKNO 3
|
|
#define INODE_BITMAP_BLOCKNO 4
|
|
#define INODE_TABLE_BLOCKNO 5
|
|
#define ROOT_DIR_BLOCKNO 21
|
|
#define LOST_AND_FOUND_DIR_BLOCKNO 22
|
|
#define HELLO_WORLD_FILE_BLOCKNO 23
|
|
#define LAST_BLOCK HELLO_WORLD_FILE_BLOCKNO
|
|
|
|
#define NUM_FREE_BLOCKS (NUM_BLOCKS - LAST_BLOCK - 1)
|
|
#define NUM_FREE_INODES (NUM_INODES - LAST_INO)
|
|
|
|
#define EXT2_BAD_INO 1
|
|
#define EXT2_ROOT_INO 2
|
|
#define EXT2_GOOD_OLD_FIRST_INO 11
|
|
|
|
#define EXT2_GOOD_OLD_REV 0
|
|
|
|
#define EXT2_S_IFSOCK 0xC000
|
|
#define EXT2_S_IFLNK 0xA000
|
|
#define EXT2_S_IFREG 0x8000
|
|
#define EXT2_S_IFBLK 0x6000
|
|
#define EXT2_S_IFDIR 0x4000
|
|
#define EXT2_S_IFCHR 0x2000
|
|
#define EXT2_S_IFIFO 0x1000
|
|
#define EXT2_S_ISUID 0x0800
|
|
#define EXT2_S_ISGID 0x0400
|
|
#define EXT2_S_ISVTX 0x0200
|
|
#define EXT2_S_IRUSR 0x0100
|
|
#define EXT2_S_IWUSR 0x0080
|
|
#define EXT2_S_IXUSR 0x0040
|
|
#define EXT2_S_IRGRP 0x0020
|
|
#define EXT2_S_IWGRP 0x0010
|
|
#define EXT2_S_IXGRP 0x0008
|
|
#define EXT2_S_IROTH 0x0004
|
|
#define EXT2_S_IWOTH 0x0002
|
|
#define EXT2_S_IXOTH 0x0001
|
|
|
|
#define EXT2_NDIR_BLOCKS 12
|
|
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
|
|
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
|
|
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
|
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
|
|
|
#define EXT2_NAME_LEN 255
|
|
#define EXT2_SUPER_MAGIC 0xEF53
|
|
|
|
struct ext2_superblock {
|
|
u32 s_inodes_count;
|
|
u32 s_blocks_count;
|
|
u32 s_r_blocks_count;
|
|
u32 s_free_blocks_count;
|
|
u32 s_free_inodes_count;
|
|
u32 s_first_data_block;
|
|
u32 s_log_block_size;
|
|
i32 s_log_frag_size;
|
|
u32 s_blocks_per_group;
|
|
u32 s_frags_per_group;
|
|
u32 s_inodes_per_group;
|
|
u32 s_mtime;
|
|
u32 s_wtime;
|
|
u16 s_mnt_count;
|
|
i16 s_max_mnt_count;
|
|
u16 s_magic;
|
|
u16 s_state;
|
|
u16 s_errors;
|
|
u16 s_minor_rev_level;
|
|
u32 s_lastcheck;
|
|
u32 s_checkinterval;
|
|
u32 s_creator_os;
|
|
u32 s_rev_level;
|
|
u16 s_def_resuid;
|
|
u16 s_def_resgid;
|
|
u32 s_pad[5];
|
|
u8 s_uuid[16];
|
|
u8 s_volume_name[16];
|
|
u32 s_reserved[229];
|
|
};
|
|
|
|
struct ext2_block_group_descriptor
|
|
{
|
|
u32 bg_block_bitmap;
|
|
u32 bg_inode_bitmap;
|
|
u32 bg_inode_table;
|
|
u16 bg_free_blocks_count;
|
|
u16 bg_free_inodes_count;
|
|
u16 bg_used_dirs_count;
|
|
u16 bg_pad;
|
|
u32 bg_reserved[3];
|
|
};
|
|
|
|
struct ext2_inode {
|
|
u16 i_mode;
|
|
u16 i_uid;
|
|
u32 i_size;
|
|
u32 i_atime;
|
|
u32 i_ctime;
|
|
u32 i_mtime;
|
|
u32 i_dtime;
|
|
u16 i_gid;
|
|
u16 i_links_count;
|
|
u32 i_blocks;
|
|
u32 i_flags;
|
|
u32 i_reserved1;
|
|
u32 i_block[EXT2_N_BLOCKS];
|
|
u32 i_version;
|
|
u32 i_file_acl;
|
|
u32 i_dir_acl;
|
|
u32 i_faddr;
|
|
u8 i_frag;
|
|
u8 i_fsize;
|
|
u16 i_pad1;
|
|
u32 i_reserved2[2];
|
|
};
|
|
|
|
struct ext2_dir_entry {
|
|
u32 inode;
|
|
u16 rec_len;
|
|
u16 name_len;
|
|
u8 name[EXT2_NAME_LEN];
|
|
};
|
|
|
|
#define errno_exit(str) \
|
|
do { int err = errno; perror(str); exit(err); } while (0)
|
|
|
|
#define dir_entry_set(entry, inode_num, str) \
|
|
do { \
|
|
char *s = str; \
|
|
size_t len = strlen(s); \
|
|
entry.inode = inode_num; \
|
|
entry.name_len = len; \
|
|
memcpy(&entry.name, s, len); \
|
|
if ((len % 4) != 0) { \
|
|
entry.rec_len = 12 + len / 4 * 4; \
|
|
} \
|
|
else { \
|
|
entry.rec_len = 8 + len; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define dir_entry_write(entry, fd) \
|
|
do { \
|
|
size_t size = entry.rec_len; \
|
|
if (write(fd, &entry, size) != size) { \
|
|
errno_exit("write"); \
|
|
} \
|
|
} while (0)
|
|
|
|
u32 get_current_time() {
|
|
time_t t = time(NULL);
|
|
if (t == ((time_t) -1)) {
|
|
errno_exit("time");
|
|
}
|
|
return t;
|
|
}
|
|
|
|
void write_superblock(int fd) {
|
|
off_t off = lseek(fd, BLOCK_OFFSET(1), SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
|
|
u32 current_time = get_current_time();
|
|
|
|
struct ext2_superblock superblock = {0};
|
|
|
|
superblock.s_inodes_count = NUM_INODES;
|
|
superblock.s_blocks_count = NUM_BLOCKS;
|
|
superblock.s_r_blocks_count = 0; //superblock
|
|
superblock.s_free_blocks_count = NUM_FREE_BLOCKS;
|
|
superblock.s_free_inodes_count = NUM_FREE_INODES;
|
|
superblock.s_first_data_block = SUPERBLOCK_BLOCKNO;
|
|
superblock.s_log_block_size = 0; /* 1024 , keep like this, but means left shifted*/
|
|
superblock.s_log_frag_size = 0; /* 1024 */
|
|
superblock.s_blocks_per_group = BLOCK_SIZE*8;
|
|
superblock.s_frags_per_group = BLOCK_SIZE*8;
|
|
superblock.s_inodes_per_group = NUM_INODES;
|
|
superblock.s_mtime = 0; /* Mount time */
|
|
superblock.s_wtime = current_time; /* Write time */
|
|
superblock.s_mnt_count = 0; /* Number of times mounted so far */
|
|
superblock.s_max_mnt_count = -1; /* Make this unlimited */
|
|
superblock.s_magic = EXT2_SUPER_MAGIC; /* ext2 Signature */
|
|
superblock.s_state = 1; /* File system is clean */
|
|
superblock.s_errors = 1; /* Ignore the error (continue on) */
|
|
superblock.s_minor_rev_level = 0; /* Leave this as 0 */
|
|
superblock.s_lastcheck = current_time; /* Last check time */
|
|
superblock.s_checkinterval = 1; /* Force checks by making them every 1 second */
|
|
superblock.s_creator_os = 0; /* Linux */
|
|
superblock.s_rev_level = 0; /* Leave this as 0 */
|
|
superblock.s_def_resuid = 0; /* root */
|
|
superblock.s_def_resgid = 0; /* root */
|
|
|
|
superblock.s_uuid[0] = 0x5A;
|
|
superblock.s_uuid[1] = 0x1E;
|
|
superblock.s_uuid[2] = 0xAB;
|
|
superblock.s_uuid[3] = 0x1E;
|
|
superblock.s_uuid[4] = 0x13;
|
|
superblock.s_uuid[5] = 0x37;
|
|
superblock.s_uuid[6] = 0x13;
|
|
superblock.s_uuid[7] = 0x37;
|
|
superblock.s_uuid[8] = 0x13;
|
|
superblock.s_uuid[9] = 0x37;
|
|
superblock.s_uuid[10] = 0xC0;
|
|
superblock.s_uuid[11] = 0xFF;
|
|
superblock.s_uuid[12] = 0xEE;
|
|
superblock.s_uuid[13] = 0xC0;
|
|
superblock.s_uuid[14] = 0xFF;
|
|
superblock.s_uuid[15] = 0xEE;
|
|
|
|
memcpy(&superblock.s_volume_name, "cs111-base", 10);
|
|
|
|
ssize_t size = sizeof(superblock);
|
|
if (write(fd, &superblock, size) != size) {
|
|
errno_exit("write");
|
|
}
|
|
}
|
|
|
|
void write_block_group_descriptor_table(int fd) {
|
|
off_t off = lseek(fd, BLOCK_OFFSET(2), SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
|
|
struct ext2_block_group_descriptor block_group_descriptor = {0};
|
|
|
|
block_group_descriptor.bg_block_bitmap = BLOCK_BITMAP_BLOCKNO ;
|
|
block_group_descriptor.bg_inode_bitmap = INODE_BITMAP_BLOCKNO;
|
|
block_group_descriptor.bg_inode_table = INODE_TABLE_BLOCKNO;
|
|
block_group_descriptor.bg_free_blocks_count = NUM_FREE_BLOCKS;
|
|
block_group_descriptor.bg_free_inodes_count = NUM_FREE_INODES;
|
|
block_group_descriptor.bg_used_dirs_count = 2;
|
|
|
|
ssize_t size = sizeof(block_group_descriptor);
|
|
if (write(fd, &block_group_descriptor, size) != size) {
|
|
errno_exit("write");
|
|
}
|
|
}
|
|
|
|
void write_block_bitmap(int fd) {
|
|
off_t off = lseek(fd, BLOCK_OFFSET(3), SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
|
|
u8 bitmap[BLOCK_SIZE] = {0};
|
|
for(int i = 0; i< 128; i++)
|
|
{
|
|
bitmap[i] = 0;
|
|
}
|
|
bitmap[0] = bitmap[1] = 0xFF;
|
|
bitmap[2] = 0x7f;
|
|
// for (int i = 3; i < BLOCK_SIZE/8;i++)
|
|
// {
|
|
// bitmap[i] = 0;
|
|
// }
|
|
bitmap[127]=0x80;
|
|
for(int i = 128; i<1024; i++)
|
|
{
|
|
bitmap[i] = 0xFF;
|
|
}
|
|
if (write(fd, bitmap, BLOCK_SIZE) != BLOCK_SIZE)
|
|
{
|
|
errno_exit("write");
|
|
}
|
|
}
|
|
|
|
void write_inode_bitmap(int fd) {
|
|
off_t off = lseek(fd, BLOCK_OFFSET(4), SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
|
|
u8 bitmap[BLOCK_SIZE] = {0};
|
|
|
|
for(int i = 0; i<16; i++)
|
|
{
|
|
bitmap[i] = 0x0;
|
|
}
|
|
|
|
bitmap[0] = 0xFF;
|
|
bitmap[1] = 0x1F;
|
|
|
|
for (int i = 16; i < BLOCK_SIZE;i++)
|
|
{
|
|
bitmap[i] = 0xFF;
|
|
}
|
|
|
|
if (write(fd, bitmap, BLOCK_SIZE) != BLOCK_SIZE)
|
|
{
|
|
errno_exit("write");
|
|
}
|
|
|
|
}
|
|
|
|
void write_inode(int fd, u32 index, struct ext2_inode *inode) {
|
|
off_t off = BLOCK_OFFSET(INODE_TABLE_BLOCKNO)
|
|
+ (index - 1) * sizeof(struct ext2_inode);
|
|
off = lseek(fd, off, SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
|
|
ssize_t size = sizeof(struct ext2_inode);
|
|
if (write(fd, inode, size) != size) {
|
|
errno_exit("write");
|
|
}
|
|
}
|
|
|
|
void write_inode_table(int fd) {
|
|
u32 current_time = get_current_time();
|
|
|
|
struct ext2_inode lost_and_found_inode = {0};
|
|
lost_and_found_inode.i_mode = EXT2_S_IFDIR
|
|
| EXT2_S_IRUSR
|
|
| EXT2_S_IWUSR
|
|
| EXT2_S_IXUSR
|
|
| EXT2_S_IRGRP
|
|
| EXT2_S_IXGRP
|
|
| EXT2_S_IROTH
|
|
| EXT2_S_IXOTH;
|
|
lost_and_found_inode.i_uid = 0;
|
|
lost_and_found_inode.i_size = 1024;
|
|
lost_and_found_inode.i_atime = current_time;
|
|
lost_and_found_inode.i_ctime = current_time;
|
|
lost_and_found_inode.i_mtime = current_time;
|
|
lost_and_found_inode.i_dtime = 0;
|
|
lost_and_found_inode.i_gid = 0;
|
|
lost_and_found_inode.i_links_count = 2;
|
|
lost_and_found_inode.i_blocks = 2; /* These are oddly 512 blocks */
|
|
lost_and_found_inode.i_block[0] = LOST_AND_FOUND_DIR_BLOCKNO;
|
|
write_inode(fd, LOST_AND_FOUND_INO, &lost_and_found_inode);
|
|
|
|
struct ext2_inode hello_world = {0};
|
|
hello_world.i_mode = EXT2_S_IFREG
|
|
| EXT2_S_IRUSR
|
|
| EXT2_S_IWUSR
|
|
| EXT2_S_IRGRP
|
|
| EXT2_S_IROTH;
|
|
hello_world.i_uid = 1000;
|
|
hello_world.i_size = 12;
|
|
hello_world.i_atime = current_time;
|
|
hello_world.i_ctime = current_time;
|
|
hello_world.i_mtime = current_time;
|
|
hello_world.i_dtime = 0;
|
|
hello_world.i_gid = 1000;
|
|
hello_world.i_links_count = 1;
|
|
hello_world.i_blocks = 2;
|
|
hello_world.i_block[0] = HELLO_WORLD_FILE_BLOCKNO;
|
|
write_inode(fd, HELLO_WORLD_INO, &hello_world);
|
|
|
|
struct ext2_inode hello = {0};
|
|
hello.i_mode = EXT2_S_IFLNK
|
|
| EXT2_S_IRUSR
|
|
| EXT2_S_IWUSR
|
|
| EXT2_S_IRGRP
|
|
| EXT2_S_IROTH;
|
|
hello.i_uid = 1000;
|
|
hello.i_size = 11;
|
|
hello.i_atime = current_time;
|
|
hello.i_ctime = current_time;
|
|
hello.i_mtime = current_time;
|
|
hello.i_dtime = 0;
|
|
hello.i_gid = 1000;
|
|
hello.i_links_count = 1;
|
|
hello.i_blocks = 0;
|
|
|
|
memcpy(hello.i_block, "hello-world", 11);
|
|
write_inode(fd, HELLO_INO, &hello);
|
|
|
|
struct ext2_inode root_inode = {0};
|
|
root_inode.i_mode = EXT2_S_IFDIR
|
|
| EXT2_S_IRUSR
|
|
| EXT2_S_IWUSR
|
|
| EXT2_S_IXUSR
|
|
| EXT2_S_IRGRP
|
|
| EXT2_S_IXGRP
|
|
| EXT2_S_IROTH
|
|
| EXT2_S_IXOTH;
|
|
root_inode.i_uid = 0;
|
|
root_inode.i_size = 1024;
|
|
root_inode.i_atime = current_time;
|
|
root_inode.i_ctime = current_time;
|
|
root_inode.i_mtime = current_time;
|
|
root_inode.i_dtime = 0;
|
|
root_inode.i_gid = 0;
|
|
root_inode.i_links_count = 3;
|
|
root_inode.i_blocks = 2;
|
|
root_inode.i_block[0] = ROOT_DIR_BLOCKNO;
|
|
write_inode(fd, EXT2_ROOT_INO, &root_inode);
|
|
}
|
|
|
|
void write_root_dir_block(int fd) {
|
|
off_t off = BLOCK_OFFSET(ROOT_DIR_BLOCKNO);
|
|
off = lseek(fd, off, SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
|
|
ssize_t bytes_remaining = BLOCK_SIZE;
|
|
|
|
struct ext2_dir_entry current_entry = {0};
|
|
dir_entry_set(current_entry, EXT2_ROOT_INO, ".");
|
|
dir_entry_write(current_entry, fd);
|
|
|
|
bytes_remaining -= current_entry.rec_len;
|
|
|
|
struct ext2_dir_entry parent_entry = {0};
|
|
dir_entry_set(parent_entry, EXT2_ROOT_INO, "..");
|
|
dir_entry_write(parent_entry, fd);
|
|
|
|
bytes_remaining -= parent_entry.rec_len;
|
|
|
|
struct ext2_dir_entry hello_world_file_entry = {0};
|
|
dir_entry_set(hello_world_file_entry, HELLO_WORLD_INO, "hello-world");
|
|
dir_entry_write(hello_world_file_entry, fd);
|
|
|
|
bytes_remaining -= hello_world_file_entry.rec_len;
|
|
|
|
struct ext2_dir_entry lf_entry = {0};
|
|
dir_entry_set(lf_entry,LOST_AND_FOUND_INO,"lost+found");
|
|
dir_entry_write(lf_entry,fd);
|
|
|
|
bytes_remaining -= lf_entry.rec_len;
|
|
|
|
struct ext2_dir_entry hello_entry = {0};
|
|
dir_entry_set(hello_entry,HELLO_INO,"hello");//how to show symlink? literally with arrow
|
|
dir_entry_write(hello_entry,fd);
|
|
|
|
bytes_remaining -= hello_entry.rec_len;
|
|
|
|
struct ext2_dir_entry fill_entry = {0};
|
|
fill_entry.rec_len = bytes_remaining;
|
|
dir_entry_write(fill_entry, fd);
|
|
|
|
}
|
|
|
|
void write_lost_and_found_dir_block(int fd) {
|
|
off_t off = BLOCK_OFFSET(LOST_AND_FOUND_DIR_BLOCKNO);
|
|
off = lseek(fd, off, SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
|
|
ssize_t bytes_remaining = BLOCK_SIZE;
|
|
|
|
struct ext2_dir_entry current_entry = {0};
|
|
dir_entry_set(current_entry, LOST_AND_FOUND_INO, ".");
|
|
dir_entry_write(current_entry, fd);
|
|
|
|
bytes_remaining -= current_entry.rec_len;
|
|
|
|
struct ext2_dir_entry parent_entry = {0};
|
|
dir_entry_set(parent_entry, EXT2_ROOT_INO, "..");
|
|
dir_entry_write(parent_entry, fd);
|
|
|
|
bytes_remaining -= parent_entry.rec_len;
|
|
|
|
struct ext2_dir_entry fill_entry = {0};
|
|
fill_entry.rec_len = bytes_remaining;
|
|
dir_entry_write(fill_entry, fd);
|
|
}
|
|
|
|
void write_hello_world_file_block(int fd) {
|
|
off_t off = BLOCK_OFFSET(HELLO_WORLD_FILE_BLOCKNO);
|
|
off = lseek(fd, off, SEEK_SET);
|
|
if (off == -1) {
|
|
errno_exit("lseek");
|
|
}
|
|
if (write(fd,"Hello world\n", 12) != 12)
|
|
{
|
|
errno_exit("write");
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int fd = open("cs111-base.img", O_CREAT | O_WRONLY, 0666);
|
|
if (fd == -1) {
|
|
errno_exit("open");
|
|
}
|
|
|
|
if (ftruncate(fd, 0)) {
|
|
errno_exit("ftruncate");
|
|
}
|
|
if (ftruncate(fd, NUM_BLOCKS * BLOCK_SIZE)) {
|
|
errno_exit("ftruncate");
|
|
}
|
|
|
|
write_superblock(fd);
|
|
write_block_group_descriptor_table(fd);
|
|
write_block_bitmap(fd);
|
|
write_inode_bitmap(fd);
|
|
write_inode_table(fd);
|
|
write_root_dir_block(fd);
|
|
write_lost_and_found_dir_block(fd);
|
|
write_hello_world_file_block(fd);
|
|
|
|
if (close(fd)) {
|
|
errno_exit("close");
|
|
}
|
|
return 0;
|
|
} |