466 lines
14 KiB
C++
466 lines
14 KiB
C++
#include "rawdisk.h"
|
|
/*****************************************************
|
|
30GB Disk low-level operation and data structure: spuerblock, inode, and buffer
|
|
cache 512 bytes sector for 1 block, 62914560 block(sector) 4K bytes sector for 1
|
|
block, 7864320 block(sector)
|
|
|
|
one inode equipped with one 512 bytes block
|
|
|
|
*****************************************************/
|
|
#define SECTOR_SIZE 512
|
|
#define IO_BLOCK_SIZE 4096
|
|
#define MAX_INODE 524288
|
|
#define MAX_BLOCKNUM MAX_INODE * 2 // 62914560
|
|
|
|
class SuperBlock {
|
|
|
|
public:
|
|
SuperBlock(const char *directory) {}
|
|
~SuperBlock() {}
|
|
static u_int64_t getFreeListHead(RawDisk &disk) {
|
|
char buffer[8] = {0};
|
|
disk.rawdisk_read(0, buffer, sizeof(buffer));
|
|
u_int64_t t = 0;
|
|
for (int j = 0; j < 8; j++)
|
|
t = t | (((u_int64_t)(unsigned char)buffer[j]) << (8 * j));
|
|
return t;
|
|
}
|
|
|
|
static void writeFreeListHead(RawDisk &disk, u_int64_t t) {
|
|
char buffer[8] = {0};
|
|
for (int j = 0; j < 8; j++) {
|
|
buffer[j] = (t >> (8 * j)) & 0xFF;
|
|
}
|
|
disk.rawdisk_write(0, buffer, sizeof(buffer));
|
|
}
|
|
|
|
static u_int64_t getFreeINodeHead(RawDisk &disk) {
|
|
char buffer[8] = {0};
|
|
disk.rawdisk_read(8, buffer, sizeof(buffer));
|
|
u_int64_t t = 0;
|
|
for (int j = 0; j < 8; j++)
|
|
t = t | (((u_int64_t)(unsigned char)buffer[j]) << (8 * j));
|
|
return t;
|
|
}
|
|
|
|
static void writeFreeINodeHead(RawDisk &disk, u_int64_t t) {
|
|
char buffer[8] = {0};
|
|
for (int j = 0; j < 8; j++) {
|
|
buffer[j] = (t >> (8 * j)) & 0xFF;
|
|
}
|
|
disk.rawdisk_write(8, buffer, sizeof(buffer));
|
|
}
|
|
};
|
|
|
|
class INode {
|
|
// direct datablocks
|
|
u_int64_t blocks[48];
|
|
// indirect address
|
|
u_int64_t single_indirect, double_indirect, triple_indirect;
|
|
// other
|
|
|
|
u_int64_t uid;
|
|
u_int64_t gid;
|
|
u_int64_t permissions;
|
|
u_int64_t size;
|
|
u_int64_t block_number;
|
|
|
|
public:
|
|
void read_get_byte(u_int64_t &t, int ¤t_pos, char *buffer) {
|
|
t = 0;
|
|
for (int j = 0; j < 8; j++)
|
|
t = t | (((u_int64_t)(unsigned char)buffer[j + current_pos]) << (8 * j));
|
|
current_pos += 8;
|
|
}
|
|
|
|
static u_int64_t read_byte_at(int current_pos, char *buffer) {
|
|
u_int64_t t = 0;
|
|
for (int j = 0; j < 8; j++)
|
|
t = t | (((u_int64_t)(unsigned char)buffer[j + current_pos]) << (8 * j));
|
|
return t;
|
|
}
|
|
|
|
void inode_construct(u_int64_t blockNumber, RawDisk &disk) {
|
|
char buffer[SECTOR_SIZE] = {0};
|
|
disk.rawdisk_read(blockNumber * SECTOR_SIZE, buffer, sizeof(buffer));
|
|
block_number = blockNumber;
|
|
int current_pos = 0;
|
|
// initialize blocks
|
|
for (int i = 0; i < 48; i++) {
|
|
read_get_byte(blocks[i], current_pos, buffer);
|
|
}
|
|
read_get_byte(single_indirect, current_pos, buffer);
|
|
read_get_byte(double_indirect, current_pos, buffer);
|
|
read_get_byte(triple_indirect, current_pos, buffer);
|
|
read_get_byte(uid, current_pos, buffer);
|
|
read_get_byte(gid, current_pos, buffer);
|
|
read_get_byte(permissions, current_pos, buffer);
|
|
read_get_byte(size, current_pos, buffer);
|
|
}
|
|
|
|
void write_get_byte(u_int64_t t, int ¤t_pos, char *buffer) {
|
|
for (int j = 0; j < 8; j++) {
|
|
buffer[j + current_pos] = t & (((u_int64_t)1 << (8)) - 1);
|
|
t >>= 8;
|
|
}
|
|
current_pos += 8;
|
|
}
|
|
|
|
static void write_byte_at(u_int64_t t, int current_pos, char *buffer) {
|
|
for (int j = 0; j < 8; j++) {
|
|
buffer[j + current_pos] = t & (((u_int64_t)1 << (8)) - 1);
|
|
t >>= 8;
|
|
}
|
|
}
|
|
|
|
void inode_save(RawDisk &disk) {
|
|
char buffer[SECTOR_SIZE] = {0};
|
|
int current_pos = 0;
|
|
for (int i = 0; i < 48; i++) {
|
|
write_get_byte(blocks[i], current_pos, buffer);
|
|
}
|
|
write_get_byte(single_indirect, current_pos, buffer);
|
|
write_get_byte(double_indirect, current_pos, buffer);
|
|
write_get_byte(triple_indirect, current_pos, buffer);
|
|
write_get_byte(uid, current_pos, buffer);
|
|
write_get_byte(gid, current_pos, buffer);
|
|
write_get_byte(permissions, current_pos, buffer);
|
|
write_get_byte(size, current_pos, buffer);
|
|
disk.rawdisk_write(block_number * SECTOR_SIZE, buffer, sizeof(buffer));
|
|
}
|
|
|
|
u_int64_t datablock_allocate_in_list(RawDisk &disk) {
|
|
// find a free data block
|
|
u_int64_t freeListHead = SuperBlock::getFreeListHead(disk);
|
|
/*
|
|
1. initialization
|
|
2. data block starting position
|
|
3. r/w between storage and rawdisk to maintain
|
|
*/
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
u_int64_t freeBlockNum = 0;
|
|
disk.rawdisk_read(freeListHead, buffer, sizeof(buffer));
|
|
for (int i = 8; i < 264; i++) {
|
|
if ((i < 263 && buffer[i] != -1) || (i == 263 && buffer[i] != 127)) {
|
|
int j = 0;
|
|
for (j = 0; j < 8; j++) {
|
|
if ((buffer[i] & (1 << j)) == 0) {
|
|
buffer[i] |= (1 << j);
|
|
break;
|
|
}
|
|
}
|
|
if (j < 8) {
|
|
freeBlockNum = freeListHead + ((i - 8) * 8 + j + 1) * IO_BLOCK_SIZE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
disk.rawdisk_write(freeListHead, buffer, sizeof(buffer));
|
|
bool notFull = false;
|
|
for (int i = 8; i < 264; i++) {
|
|
if ((i < 263 && buffer[i] != -1) || (i == 263 && buffer[i] != 127)) {
|
|
notFull = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!notFull) {
|
|
printf("HEADER REMOVAL DETECTED %llu %llu\n", freeListHead, freeBlockNum);
|
|
u_int64_t next_header = read_byte_at(0, buffer);
|
|
SuperBlock::writeFreeListHead(disk, next_header);
|
|
}
|
|
return freeBlockNum;
|
|
}
|
|
|
|
bool allo_single_indirect(RawDisk &disk, u_int64_t &single_i,
|
|
u_int64_t freeBlockNum) {
|
|
if (single_i == 0) {
|
|
|
|
single_i = datablock_allocate_in_list(disk);
|
|
}
|
|
bool inSingle = false;
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
disk.rawdisk_read(single_i, buffer, sizeof(buffer));
|
|
for (int i = 0; i < IO_BLOCK_SIZE; i += 8) {
|
|
u_int64_t addr = read_byte_at(i, buffer);
|
|
if (addr == 0) {
|
|
inSingle = true;
|
|
write_byte_at(freeBlockNum, i, buffer);
|
|
disk.rawdisk_write(single_i, buffer, sizeof(buffer));
|
|
break;
|
|
}
|
|
}
|
|
return inSingle;
|
|
}
|
|
|
|
bool allo_double_indirect(RawDisk &disk, u_int64_t &double_i,
|
|
u_int64_t freeBlockNum) {
|
|
if (double_i == 0) {
|
|
double_i = datablock_allocate_in_list(disk);
|
|
}
|
|
bool inDouble = false;
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
disk.rawdisk_read(double_i, buffer, sizeof(buffer));
|
|
for (int i = 0; i < IO_BLOCK_SIZE; i += 8) {
|
|
u_int64_t addr = read_byte_at(i, buffer);
|
|
bool flag = allo_single_indirect(disk, addr, freeBlockNum);
|
|
if (flag) {
|
|
write_byte_at(addr, i, buffer);
|
|
disk.rawdisk_write(double_i, buffer, sizeof(buffer));
|
|
inDouble = true;
|
|
break;
|
|
}
|
|
}
|
|
return inDouble;
|
|
}
|
|
|
|
bool allo_triple_indirect(RawDisk &disk, u_int64_t &triple_i,
|
|
u_int64_t freeBlockNum) {
|
|
if (triple_i == 0) {
|
|
triple_i = datablock_allocate_in_list(disk);
|
|
}
|
|
bool inTriple = false;
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
disk.rawdisk_read(triple_i, buffer, sizeof(buffer));
|
|
for (int i = 0; i < IO_BLOCK_SIZE; i += 8) {
|
|
u_int64_t addr = read_byte_at(i, buffer);
|
|
bool flag = allo_double_indirect(disk, addr, freeBlockNum);
|
|
if (flag) {
|
|
write_byte_at(addr, i, buffer);
|
|
disk.rawdisk_write(triple_i, buffer, sizeof(buffer));
|
|
inTriple = true;
|
|
break;
|
|
}
|
|
}
|
|
return inTriple;
|
|
}
|
|
|
|
// allowcate 1 datablock and add to the end of the file
|
|
u_int64_t datablock_allocate(RawDisk &disk) {
|
|
// do we need to check dynamic?
|
|
|
|
// add the data block to blocks, single, double, triple
|
|
u_int64_t freeBlockNum = datablock_allocate_in_list(disk);
|
|
bool inBlocks = false;
|
|
for (int i = 0; i < 48; i++)
|
|
if (blocks[i] == 0) {
|
|
inBlocks = true;
|
|
blocks[i] = freeBlockNum;
|
|
break;
|
|
}
|
|
if (!inBlocks) {
|
|
bool inSingle = allo_single_indirect(disk, single_indirect, freeBlockNum);
|
|
if (!inSingle) {
|
|
bool inDouble =
|
|
allo_double_indirect(disk, double_indirect, freeBlockNum);
|
|
if (!inDouble) {
|
|
bool inTriple =
|
|
allo_triple_indirect(disk, triple_indirect, freeBlockNum);
|
|
// wait to deal with too big files
|
|
}
|
|
}
|
|
}
|
|
|
|
// return the block number
|
|
inode_save(disk);
|
|
return freeBlockNum;
|
|
}
|
|
|
|
void datablock_deallocate_in_list(u_int64_t freeBlockNum, RawDisk &disk) {
|
|
// find the related 2048block head
|
|
u_int64_t freeBlockHead =
|
|
((freeBlockNum / SECTOR_SIZE - MAX_INODE) / (8 * 2048) * (8 * 2048) +
|
|
MAX_INODE) *
|
|
SECTOR_SIZE;
|
|
|
|
// mark it alive in its bitmap
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
bool notEmpty = false;
|
|
disk.rawdisk_read(freeBlockHead, buffer, sizeof(buffer));
|
|
for (int i = 8; i < 264; i++) {
|
|
if (buffer[i] != 0) {
|
|
notEmpty = true;
|
|
}
|
|
}
|
|
u_int64_t inBlockPos = (freeBlockNum - freeBlockHead) / IO_BLOCK_SIZE - 1;
|
|
buffer[8 + inBlockPos / 8] &= (-1) ^ (1 << (inBlockPos % 8));
|
|
|
|
// if its bitmap was 0, add it back to the list head
|
|
if (!notEmpty) {
|
|
u_int64_t freeListHead = SuperBlock::getFreeListHead(disk);
|
|
write_byte_at(freeListHead, 0, buffer);
|
|
SuperBlock::writeFreeListHead(disk, freeBlockHead);
|
|
}
|
|
disk.rawdisk_write(freeBlockHead, buffer, sizeof(buffer));
|
|
}
|
|
|
|
u_int64_t deallo_single_indirect(RawDisk &disk, u_int64_t &single_i) {
|
|
if (single_i == 0) {
|
|
return 0;
|
|
}
|
|
u_int64_t freeBlockNum = 0;
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
int delpoint = -1;
|
|
disk.rawdisk_read(single_i, buffer, sizeof(buffer));
|
|
for (int i = 4088; i >= 0; i--) {
|
|
u_int64_t addr = read_byte_at(i, buffer);
|
|
if (addr != 0) {
|
|
freeBlockNum = addr;
|
|
addr = 0;
|
|
write_byte_at(addr, i, buffer);
|
|
delpoint = i;
|
|
break;
|
|
}
|
|
}
|
|
disk.rawdisk_write(single_i, buffer, sizeof(buffer));
|
|
u_int64_t addr = read_byte_at(0, buffer);
|
|
if (delpoint == 0 && addr == 0) {
|
|
datablock_deallocate_in_list(single_i, disk);
|
|
single_i = 0;
|
|
}
|
|
return freeBlockNum;
|
|
}
|
|
|
|
bool deallo_double_indirect(RawDisk &disk, u_int64_t &double_i) {
|
|
if (double_i == 0) {
|
|
return false;
|
|
}
|
|
u_int64_t freeBlockNum = 0;
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
int delpoint = -1;
|
|
disk.rawdisk_read(double_i, buffer, sizeof(buffer));
|
|
for (int i = 4088; i >= 0; i -= 8) {
|
|
u_int64_t addr = read_byte_at(i, buffer);
|
|
u_int64_t inSingle = deallo_single_indirect(disk, addr);
|
|
if (inSingle) {
|
|
freeBlockNum = inSingle;
|
|
write_byte_at(addr, i, buffer);
|
|
delpoint = i;
|
|
break;
|
|
}
|
|
}
|
|
disk.rawdisk_write(double_i, buffer, sizeof(buffer));
|
|
u_int64_t addr = read_byte_at(0, buffer);
|
|
if (delpoint == 0 && addr == 0) {
|
|
datablock_deallocate_in_list(double_i, disk);
|
|
double_i = 0;
|
|
}
|
|
return freeBlockNum;
|
|
}
|
|
|
|
bool deallo_triple_indirect(RawDisk &disk, u_int64_t &triple_i) {
|
|
if (triple_i == 0) {
|
|
return false;
|
|
}
|
|
u_int64_t freeBlockNum = 0;
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
int delpoint = -1;
|
|
disk.rawdisk_read(triple_i, buffer, sizeof(buffer));
|
|
for (int i = 4088; i >= 0; i -= 8) {
|
|
u_int64_t addr = read_byte_at(i, buffer);
|
|
u_int64_t inDouble = deallo_double_indirect(disk, addr);
|
|
if (inDouble) {
|
|
freeBlockNum = inDouble;
|
|
write_byte_at(addr, i, buffer);
|
|
delpoint = i;
|
|
break;
|
|
}
|
|
}
|
|
disk.rawdisk_write(triple_i, buffer, sizeof(buffer));
|
|
u_int64_t addr = read_byte_at(0, buffer);
|
|
if (delpoint == 0 && addr == 0) {
|
|
datablock_deallocate_in_list(triple_i, disk);
|
|
triple_i = 0;
|
|
}
|
|
return freeBlockNum;
|
|
}
|
|
|
|
// deallocate 1 datablock from the end of the file
|
|
u_int64_t datablock_deallocate(RawDisk &disk) {
|
|
// find the last datablock and remove it from inode (triple->direct)
|
|
u_int64_t freeBlockNum = 0;
|
|
freeBlockNum = deallo_triple_indirect(disk, triple_indirect);
|
|
if (!freeBlockNum) {
|
|
freeBlockNum = deallo_double_indirect(disk, double_indirect);
|
|
if (!freeBlockNum) {
|
|
freeBlockNum = deallo_single_indirect(disk, single_indirect);
|
|
if (!freeBlockNum) {
|
|
for (int i = 47; i >= 0; i--)
|
|
if (blocks[i] != 0) {
|
|
freeBlockNum = blocks[i];
|
|
blocks[i] = 0;
|
|
break;
|
|
}
|
|
// deal with empty
|
|
}
|
|
}
|
|
}
|
|
|
|
// add it back to freeBlocklist
|
|
datablock_deallocate_in_list(freeBlockNum, disk);
|
|
inode_save(disk);
|
|
return freeBlockNum;
|
|
}
|
|
};
|
|
|
|
class INodeOperation {
|
|
// free list head is at super block (0): first 8 bytes
|
|
|
|
public:
|
|
// initialization of the rawdisk
|
|
void initialize(RawDisk &disk) {
|
|
// initialize Inode list head
|
|
SuperBlock::writeFreeINodeHead(disk, 1);
|
|
for (u_int64_t i = 1; i < MAX_INODE; i++) {
|
|
char buffer[SECTOR_SIZE] = {0};
|
|
u_int64_t t = i + 1;
|
|
if (t < MAX_INODE) {
|
|
for (int j = 0; j < 8; j++) {
|
|
buffer[j] = (t >> (8 * j)) & 0xFF;
|
|
}
|
|
}
|
|
disk.rawdisk_write(i * SECTOR_SIZE, buffer, sizeof(buffer));
|
|
}
|
|
SuperBlock::writeFreeListHead(
|
|
disk, MAX_INODE * SECTOR_SIZE); // maximum inode number 2^19 0x80000
|
|
// Have tested this initialize function but MAX_BLOCK too much, MAX_INODE*2
|
|
// works
|
|
for (u_int64_t i = MAX_INODE; i < MAX_BLOCKNUM - 4096; i += 2048 * 8) {
|
|
char buffer[IO_BLOCK_SIZE] = {0};
|
|
u_int64_t t = (i + 2048 * 8) * SECTOR_SIZE;
|
|
// t is address, storing in to buffer
|
|
for (int j = 0; j < 8; j++) {
|
|
buffer[j] = (t >> (8 * j)) & 0xFF;
|
|
}
|
|
disk.rawdisk_write(i * SECTOR_SIZE, buffer, sizeof(buffer));
|
|
}
|
|
}
|
|
|
|
// allocate an inode from free inode list head and return the number of the
|
|
// inode the i-th inode is in the i-th block
|
|
u_int64_t inode_allocate(RawDisk &disk) {
|
|
u_int64_t freeINodeHead = SuperBlock::getFreeINodeHead(disk);
|
|
char buffer[SECTOR_SIZE] = {0};
|
|
disk.rawdisk_read(freeINodeHead * SECTOR_SIZE, buffer, sizeof(buffer));
|
|
u_int64_t newINodeHead = INode::read_byte_at(0, buffer);
|
|
// deal with no more INode
|
|
SuperBlock::writeFreeINodeHead(disk, newINodeHead);
|
|
// to do: initialize the INode on disk at freeINodeHead
|
|
|
|
// return inode number
|
|
return freeINodeHead;
|
|
}
|
|
|
|
// free the inode and add it to the free inode list head
|
|
void inode_free(RawDisk &disk, u_int64_t INodeNumber) {
|
|
u_int64_t freeINodeHead = SuperBlock::getFreeINodeHead(disk);
|
|
char buffer[SECTOR_SIZE] = {0};
|
|
INode::write_byte_at(freeINodeHead, 0, buffer);
|
|
disk.rawdisk_write(INodeNumber * SECTOR_SIZE, buffer, sizeof(buffer));
|
|
SuperBlock::writeFreeINodeHead(disk, INodeNumber);
|
|
}
|
|
|
|
// ignore for now
|
|
void inode_read() {}
|
|
|
|
void inode_write() {}
|
|
}; |