Select Git revision
minix.c 11.23 KiB
#include "minix.h"
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int unmarshal_sb(struct minix_super_block *sb, const char *img_filepath) {
int fd = open(img_filepath, O_RDONLY);
if (fd == -1) {
perror("open");
close(fd);
return -1;
}
lseek(fd, BLOCK_SIZE, SEEK_SET);
if (read(fd, sb, sizeof(struct minix_super_block)) == -1) {
perror("read");
close(fd);
return -1;
}
if (sb->s_magic != MINIX_MAGIC) {
fprintf(stderr, "The provided image isn't a minix-FS image whose magic "
"value is 0x137F\n");
close(fd);
return -1;
}
close(fd);
return 0;
}
int unmarshal_inode(struct minix_inode *inode, const uint32_t inode_nb,
const char *img_filepath) {
struct minix_super_block sb = {0};
if (unmarshal_sb(&sb, img_filepath) == -1) {
perror("marshal_sb");
return -1;
}
int fd = open(img_filepath, O_RDONLY);
if (fd == -1) {
perror("open");
close(fd);
return -1;
}
lseek(fd, BLOCK_SIZE * BITMAP_INODE_FIRST_IDX, SEEK_SET);
if (inode_nb == 0 || inode_nb > sb.s_ninodes ||
!is_inode_allocated(inode_nb, img_filepath)) {
fprintf(stderr, "Inode isn't allocated or inode value is invalid\n");
return -1;
}
uint16_t inode_table_size = sb.s_ninodes / sizeof(struct minix_inode);
uint16_t idx_first_block_inode_table =
sb.s_firstdatazone - inode_table_size;
lseek(fd,
BLOCK_SIZE * idx_first_block_inode_table +
((inode_nb - 1) * sizeof(struct minix_inode)),
SEEK_SET);
if (read(fd, inode, sizeof(struct minix_inode)) == -1) {
perror("open");
close(fd);
return -1;
}
close(fd);
return 0;
}
bool is_inode_allocated(const uint32_t inode_nb, const char *img_filepath) {
int fd = open(img_filepath, O_RDONLY);
if (fd == -1) {
perror("open");
close(fd);
return -1;
}
// Computes in which block of the inode's bitmap is the bit associated
// to the given inode number
int inode_bitmap_block = (inode_nb / (BLOCK_SIZE * BYTE_BITSIZE)) + 1;
char buf[BLOCK_SIZE] = {0};
lseek(fd, BLOCK_SIZE * BITMAP_INODE_FIRST_IDX * inode_bitmap_block,
SEEK_SET);
// Checking if we've read an entire block or not
ssize_t bytes_read = read(fd, buf, BLOCK_SIZE);
if (bytes_read == -1) {
perror("read");
close(fd);
return false;
}
if (bytes_read == BLOCK_SIZE) {
uint16_t byte_idx = inode_nb / BYTE_BITSIZE;
uint8_t bit_idx = inode_nb % BYTE_BITSIZE;
close(fd);
return buf[byte_idx] & (0x01 << bit_idx);
}
close(fd);
return false;
}
int read_sb(const struct minix_super_block *sb) {
if (sb->s_magic != MINIX_MAGIC) {
fprintf(stdout, "Wrong magic value\n");
return -1;
}
uint16_t inode_table_size = sb->s_ninodes / sizeof(struct minix_inode);
uint16_t idx_first_block_inode_table =
sb->s_firstdatazone - inode_table_size;
fprintf(stdout, "========= MINIX Superblock =========\n");
fprintf(stdout, "Signature (Magic) :\t0x%x\n", sb->s_magic);
fprintf(stdout, "Total number of inodes :\t%d\n", sb->s_ninodes);
fprintf(stdout, "Total number of blocks :\t%d\n", sb->s_nzones);
fprintf(stdout, "Size of inode bitmap (in blocks) :\t%d\n",
sb->s_imap_blocks);
fprintf(stdout, "Size of data bitmap (in blocks) :\t%d\n",
sb->s_zmap_blocks);
fprintf(stdout, "Size of inode table (in blocks) :\t%d\n",
inode_table_size);
fprintf(stdout, "Index of first inode bitmap block :\t%d\n",
BITMAP_INODE_FIRST_IDX);
fprintf(stdout, "Index of first data bitmap block :\t%d\n",
BITMAP_INODE_FIRST_IDX + sb->s_imap_blocks);
fprintf(stdout, "Index of first inode table block:\t%d\n",
idx_first_block_inode_table);
fprintf(stdout, "Index of first data block:\t%d\n", sb->s_firstdatazone);
return 0;
}
int read_inode(const struct minix_inode *inode) {
uint16_t file_type = inode->i_mode >> 12;
fprintf(stdout, "========= MINIX inode =========\n");
fprintf(stdout, "File type : ");
switch (file_type) {
case 0x1:
fprintf(stdout, "named pipe (FIFO)\n");
break;
case 0x2:
fprintf(stdout, "char device\n");
break;
case 0x4:
fprintf(stdout, "directory\n");
break;
case 0x6:
fprintf(stdout, "block device\n");
break;
case 0x8:
fprintf(stdout, "regular file\n");
break;
case 0xA:
fprintf(stdout, "symbolic link\n");
break;
default:
fprintf(stdout, "invalid file type\n");
return -1;
}
// User Group Other (ugo) - permissions
char permissions[12] = {0};
uint16_t ugo = inode->i_mode & 0x1FF;
uint8_t user = (ugo >> 6) & 0x7;
uint8_t group = (ugo >> 3) & 0x7;
uint8_t other = ugo & 0x7;
uint8_t buf[3] = {user, group, other};
for (size_t i = 0; i < 3; i++) {
switch (buf[i]) {
case 0:
strncat(permissions, "___", 3);
break;
case 1:
strncat(permissions, "__x", 3);
break;
case 2:
strncat(permissions, "_w_", 3);
break;
case 3:
strncat(permissions, "_wx", 3);
break;
case 4:
strncat(permissions, "r__", 3);
break;
case 5:
strncat(permissions, "r_x", 3);
break;
case 6:
strncat(permissions, "rw_", 3);
break;
case 7:
strncat(permissions, "rwx", 3);
break;
}
strncat(permissions, " ", 1);
}
fprintf(stdout, "Permissions : %s\n", permissions);
fprintf(stdout, "UID : %d\n", inode->i_uid);
fprintf(stdout, "GID : %d\n", inode->i_gid);
fprintf(stdout, "Size (in bytes) : %d\n", inode->i_size);
fprintf(stdout, "NB links : %d\n", inode->i_nlinks);
return 0;
}
int read_indir_block(uint16_t *buf, const char *img_filepath,
const size_t block_number) {
int fd = open(img_filepath, O_RDONLY);
if (fd == -1) {
perror("open");
close(fd);
return -1;
}
lseek(fd, BLOCK_SIZE * block_number, SEEK_SET);
ssize_t bytes_read = read(fd, buf, BLOCK_SIZE);
if (bytes_read == -1) {
perror("read");
close(fd);
return -1;
}
if (bytes_read < BLOCK_SIZE) {
fprintf(stderr, "The entire block hasn't been read\n");
close(fd);
return -1;
}
close(fd);
return 0;
}
ssize_t bmap(const struct minix_inode *inode, const char *img_filepath,
size_t logical_block) {
size_t direct_zone_len = sizeof(inode->i_zone) / sizeof(inode->i_zone[0]);
size_t ptr_by_block = BLOCK_SIZE / sizeof(inode->i_indir_zone);
if (logical_block < direct_zone_len) {
return inode->i_zone[logical_block];
}
logical_block -= direct_zone_len;
if (logical_block < ptr_by_block) {
uint16_t buf[BLOCK_SIZE] = {0};
if (read_indir_block(buf, img_filepath, inode->i_indir_zone) == -1) {
fprintf(stderr, "read_indir_block failed\n");
return -1;
}
return buf[logical_block];
}
logical_block -= ptr_by_block;
if (logical_block < (ptr_by_block * ptr_by_block)) {
uint16_t buf1[BLOCK_SIZE] = {0};
uint16_t buf2[BLOCK_SIZE] = {0};
if (read_indir_block(buf1, img_filepath, inode->i_dbl_indir_zone) ==
-1) {
fprintf(stderr, "read_indir_block failed\n");
return -1;
}
if (read_indir_block(buf2, img_filepath,
buf1[logical_block / ptr_by_block]) == -1) {
fprintf(stderr, "read_indir_block failed\n");
return -1;
}
return buf2[logical_block % BLOCK_SIZE * sizeof(uint16_t)];
}
return 0;
}
int read_data_block(char *buf, const char *img_filepath,
size_t phys_num_block) {
int fd = open(img_filepath, O_RDONLY);
if (fd == -1) {
perror("open");
close(fd);
return -1;
}
lseek(fd, BLOCK_SIZE * phys_num_block, SEEK_SET);
ssize_t bytes_read = read(fd, buf, BLOCK_SIZE);
if (bytes_read == -1) {
perror("open");
close(fd);
return -1;
}
if (bytes_read != BLOCK_SIZE) {
close(fd);
return -1;
}
close(fd);
return 0;
}
int lookup_entry(const struct minix_inode *inode, const char *token,
const char *img_filepath) {
int nb_blocks_used = inode->i_size / BLOCK_SIZE;
if (inode->i_size % BLOCK_SIZE != 0) {
nb_blocks_used++;
}
for (int i = 0; i < nb_blocks_used; i++) {
ssize_t phys_num = bmap(inode, img_filepath, i);
if (phys_num == -1) {
fprintf(stderr, "bmap has failed...\n");
return -1;
}
char buf[BLOCK_SIZE + 1] = {0};
if (read_data_block(buf, img_filepath, phys_num) == -1) {
fprintf(stderr, "read_data_block has failed...\n");
return -1;
}
struct minix_dir_entry dir_entry = {0};
for (size_t j = 0; j < BLOCK_SIZE / sizeof(struct minix_dir_entry);
j++) {
memcpy(&dir_entry, &buf[j * sizeof(struct minix_dir_entry)],
sizeof(struct minix_dir_entry));
if (strncmp(dir_entry.name, token, strlen(dir_entry.name)) == 0) {
return dir_entry.inode;
}
}
}
return -1;
}
int namei(const char *img_filepath, char *filepath) {
struct minix_inode inode = {0};
if (unmarshal_inode(&inode, 1, img_filepath) == -1) {
fprintf(stderr, "marshal_inode has failed\n");
return -1;
}
char *token = strtok(filepath, "/");
int next_inode = 0;
while (token != NULL) {
// fprintf(stdout, "token = %s\n\n", token);
next_inode = lookup_entry(&inode, token, img_filepath);
switch (next_inode) {
case -1:
fprintf(stderr, "lookup_entry has failed\n");
return -1;
case 0:
fprintf(stderr, "file doesn't exist\n");
return -1;
default:
token = strtok(NULL, "/");
memset(&inode, 0, sizeof(struct minix_inode));
if (unmarshal_inode(&inode, next_inode, img_filepath) == -1) {
fprintf(stderr, "marshal_inode has failed\n");
return -1;
}
}
}
int nb_blocks_used = inode.i_size / BLOCK_SIZE;
if (inode.i_size % BLOCK_SIZE != 0) {
nb_blocks_used++;
}
for (int i = 0; i < nb_blocks_used; i++) {
ssize_t phys_num = bmap(&inode, img_filepath, i);
if (phys_num == -1) {
fprintf(stderr, "bmap has failed...\n");
return -1;
}
char buf[BLOCK_SIZE + 1] = {0};
if (read_data_block(buf, img_filepath, phys_num) == -1) {
fprintf(stderr, "read_data_block has failed...\n");
return -1;
}
fprintf(stdout, "%s", buf);
}
fprintf(stdout, "\n");
return 0;
}