Created
July 29, 2016 21:18
-
-
Save Deamon5550/4184568d1b295f2d807073bc43a583ff to your computer and use it in GitHub Desktop.
My own filesystem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "LLFS.h" | |
#include <iostream> | |
#define BLOCK_SIZE 512 | |
#define BLOCK_COUNT 4096 | |
namespace Filesystem { | |
void format(char *disk) { | |
std::cout << "Formatting llfs disk '" << disk << "'\n"; | |
char *data = (char *) malloc(BLOCK_SIZE * BLOCK_COUNT); | |
memset(data, 0, BLOCK_SIZE * BLOCK_COUNT); | |
superblock_t *superblock = (superblock_t *) data; | |
superblock->type = 0x53464C4C; | |
superblock->file_count = 1; | |
superblock->inode_count = 1; | |
printf(" Marking all blocks as available except superblock and inode blocks\n"); | |
// mark all blocks as available, except the first 10, and the inode blocks | |
char *free_blocks = (char *) data + 512; | |
memset(free_blocks, 0xFF, 512); | |
for (int i = 0; i < 4096; i++) { | |
if (i < 10 || (i % 256) == 255) { | |
free_blocks[i / 8] &= ~(1 << (i % 8)); | |
} | |
} | |
printf(" Marking all inodes as available\n"); | |
char *free_inodes = (char *) data + 1024; | |
memset(free_inodes, 0xFF, 32); | |
printf(" Allocating first inode for root directory\n"); | |
free_inodes[0] &= ~(1); | |
inode_t *rootInode = (inode_t *) data + (255 * 16); | |
rootInode->file_size = 512; | |
rootInode->file_type = FileType::DIR; | |
rootInode->blocks[0] = 10; | |
printf(" Allocating first block for root directory\n"); | |
free_blocks[1] &= ~(1 << (2)); | |
char *dir = data + 10 * 512; | |
strncpy(dir + 1, ".", 30); | |
strncpy(dir + 33, "..", 30); | |
for (int i = 2; i < 16; i++) { | |
dir[i*32] = (unsigned char) 0xFF; | |
} | |
std::FILE *fdisk = fopen(disk, "w+"); | |
fwrite(data, 1, 512 * 4096, fdisk); | |
fclose(fdisk); | |
free(data); | |
} | |
LLFS *mount(char *disk) { | |
std::FILE *fdisk = fopen(disk, "r+"); | |
LLFS *fs = new LLFS(fdisk); | |
return fs; | |
} | |
void unmount(LLFS *fs) { | |
fs->sync(); | |
} | |
LLFS::LLFS(std::FILE *fdisk) : disk(fdisk) { | |
superblock = (superblock_t *) malloc(512); | |
free_blocks = (char *) malloc(512); | |
free_inodes = (char *) malloc(32); | |
fseek(disk, 0, SEEK_SET); | |
fread(superblock, 1, 512, disk); | |
fread(free_blocks, 1, 512, disk); | |
fread(free_inodes, 1, 32, disk); | |
for (int i = 0; i < 32; i++) { | |
inode_block_cache[i] = nullptr; | |
} | |
open_files_size = 32; | |
open_files_index = 0; | |
open_files = (File**) malloc(sizeof(File *) * open_files_size); | |
static_cache_size = 0; | |
static_cache_index = 0; | |
static_cache = nullptr; | |
dynamic_cache_size = 32; | |
dynamic_cache_index = 0; | |
dynamic_cache = (BlockCacheEntry **) malloc(sizeof(BlockCacheEntry*) * dynamic_cache_size); | |
root = new File(this, nullptr, "/", "/", 0, getInode(0), true); | |
} | |
/*LLFS::~LLFS() { | |
sync(); | |
fclose(disk); | |
delete superblock; | |
delete free_blocks; | |
delete free_inodes; | |
for (int i = 0; i < 32; i++) { | |
if (inode_block_cache[i] != nullptr) { | |
delete inode_block_cache[i]; | |
} | |
} | |
for (int i = 0; i < open_files_index; i++) { | |
delete open_files[i]; | |
} | |
delete root; | |
delete open_files; | |
delete[] inode_block_cache; | |
}*/ | |
File *LLFS::open(char *path) { | |
if (strcmp("/", path) == 0) { | |
return root; | |
} | |
for (int i = 0; i < open_files_index; i++) { | |
if (strcmp(open_files[i]->getName(), path) == 0) { | |
std::cout << "File already open\n"; | |
return nullptr; | |
} | |
} | |
int len = strlen(path); | |
char part[50]; | |
File *parent = root; | |
int o = 0; | |
for (int i = 1; i < len; i++) { | |
char next = path[i]; | |
if (next == '/') { | |
part[o] = '\0'; | |
parent = parent->getChildDir(part); | |
o = 0; | |
} else { | |
part[o++] = next; | |
} | |
} | |
part[o] = '\0'; | |
if (o == 0) { | |
return parent; | |
} | |
File *file = parent->getChild(part); | |
open_files[open_files_index++] = file; | |
return file; | |
} | |
void LLFS::close(File *file) { | |
bool found = false; | |
for (int i = 0; i < open_files_index; i++) { | |
if (found) { | |
open_files[i - 1] = open_files[i]; | |
} else { | |
if (open_files[i] == file) { | |
found = true; | |
} | |
} | |
} | |
if (found) { | |
open_files_index--; | |
} | |
delete file; | |
} | |
inode_t *LLFS::getInode(int number) { | |
int inode_block = number / 16; | |
if (inode_block_cache[inode_block] == nullptr) { | |
std::cout << "Loading inode block " << inode_block << "\n"; | |
char *inode_block_data = (char *) malloc(512); | |
fseek(disk, (inode_block * 256 + 255) * 512, SEEK_SET); | |
fread(inode_block_data, 1, 512, disk); | |
inode_block_cache[inode_block] = inode_block_data; | |
} | |
std::cout << "getting inode " << number << "\n"; | |
inode_t *inode = (inode_t *) (inode_block_cache[inode_block] + (number % 16) * 32); | |
return inode; | |
} | |
unsigned int LLFS::createInode() { | |
int number = -1; | |
// TODO continue from same point each time | |
for (int i = 0; i < 32; i++) { | |
unsigned char next = free_inodes[i]; | |
if (next != 0) { | |
int o; | |
for (o = 0; o < 8; o++) { | |
if (((next >> o) & 1) == 1) { | |
number = i * 8 + o; | |
break; | |
} | |
} | |
break; | |
} | |
} | |
if (number == -1) { | |
printf("Error: no free inodes for allocation"); | |
return NULL; | |
} | |
free_inodes[number / 8] &= ~(1 << (number % 8)); | |
printf("Allocating inode %d\n", number); | |
superblock->inode_count++; | |
return number; | |
} | |
BlockCacheEntry *LLFS::allocateBlock() { | |
int number = -1; | |
// TODO continue from same point each time | |
for (int i = 0; i < 512; i++) { | |
unsigned char next = free_blocks[i]; | |
if (next != 0) { | |
int o; | |
for (o = 0; o < 8; o++) { | |
if (((next >> o) & 1) == 1) { | |
number = i * 8 + o; | |
break; | |
} | |
} | |
break; | |
} | |
} | |
if (number == -1) { | |
printf("Error: no free blocks for allocation"); | |
return nullptr; | |
} | |
free_blocks[number / 8] &= ~(1 << (number % 8)); | |
printf("Allocating block %d\n", number); | |
return getBlock(number); | |
} | |
void LLFS::sync() { | |
fseek(disk, 0, SEEK_SET); | |
fwrite(superblock, 1, 512, disk); | |
fwrite(free_blocks, 1, 512, disk); | |
fwrite(free_inodes, 1, 32, disk); | |
// if we crash here then we just have to notice that an inode/block is ununsed when we walk the tree | |
for (int i = 0; i < 32; i++) { | |
if (inode_block_cache[i] != nullptr) { | |
std::cout << "Saving inode block " << i << "\n"; | |
fseek(disk, (i * 256 + 255) * 512, SEEK_SET); | |
fwrite(inode_block_cache[i], 1, 512, disk); | |
} | |
} | |
// if we crash below here then we lost data but not consistency | |
for (int i = 0; i < dynamic_cache_index; i++) { | |
BlockCacheEntry *entry = dynamic_cache[i]; | |
if (entry->modified) { | |
fseek(disk, entry->number * 512, SEEK_SET); | |
fwrite(entry->block, 1, 512, disk); | |
} | |
delete entry; | |
dynamic_cache[i] = nullptr; | |
} | |
dynamic_cache_index = 0; | |
} | |
BlockCacheEntry *LLFS::getBlock(int number) { | |
if (static_cache_index > 0) { | |
} | |
if (dynamic_cache_index > 0) { | |
for (int i = 0; i < dynamic_cache_index; i++) { | |
BlockCacheEntry *entry = dynamic_cache[i]; | |
if (entry->number == number) { | |
std::cout << "Fetched block " << number << " from dynamic cache\n"; | |
return entry; | |
} | |
} | |
} | |
if (dynamic_cache_index == dynamic_cache_size) { | |
std::cout << "Dynamic cache full, syncing to disk\n"; | |
sync(); | |
} | |
std::cout << "Loading block " << number << " from disk\n"; | |
char *block = (char*) malloc(512); | |
fseek(disk, number*512, SEEK_SET); | |
fread(block, 1, 512, disk); | |
BlockCacheEntry *entry = new BlockCacheEntry(number, block); | |
dynamic_cache[dynamic_cache_index++] = entry; | |
return entry; | |
} | |
std::FILE *LLFS::getDisk() { | |
return disk; | |
} | |
void LLFS::releaseBlock(int num) { | |
free_blocks[num/8] |= (1 << (num % 8)); | |
std::cout << "Releasing block " << num << "\n"; | |
} | |
void LLFS::releaseInode(int num) { | |
free_inodes[num / 8] |= (1 << (num % 8)); | |
int inode_block = num / 16; | |
if (inode_block_cache[inode_block] == nullptr) { | |
std::cout << "Loading inode block " << inode_block << "\n"; | |
char *inode_block_data = (char *) malloc(512); | |
fseek(disk, (inode_block * 256 + 255) * 512, SEEK_SET); | |
fread(inode_block_data, 1, 512, disk); | |
inode_block_cache[inode_block] = inode_block_data; | |
} | |
memset(inode_block_cache[inode_block] + (num % 16) * 32, 0, 32); | |
std::cout << "Releasing inode " << num << "\n"; | |
} | |
File::File(LLFS *fs, File *parent, char *name, char *path, int inode_number, inode_t *in, bool isDir) : | |
fs(fs), parent(parent), file_name(name), file_path(path), inode(in), isDir(isDir), inode_number(inode_number) { | |
std::cout << "Creating file '" << path << " \n"; | |
created = inode != nullptr; | |
seek_pos = 0; | |
if (isDir) { | |
entries = (DirectoryEntry**) malloc(sizeof(DirectoryEntry*) * 32); | |
entries_size = 32; | |
entries_index = 0; | |
if (created) { | |
BlockCacheEntry *data = fs->getBlock(inode->blocks[0]); | |
char *block = data->block; | |
for (int i = 0; i < 16; i++) { | |
unsigned char inode = block[i * 32]; | |
if (inode != 0xFF) { | |
char *fname = (char*) malloc(31); | |
memset(fname, 0, 31); | |
strncpy(fname, (char *) (block + i * 32 + 1), 30); | |
DirectoryEntry *entry = new DirectoryEntry(inode, fname); | |
std::cout << "Loaded dir entry " << fname << " for directory " << file_path << "\n"; | |
entries[entries_index++] = entry; | |
} | |
} | |
} | |
} else { | |
entries = nullptr; | |
entries_size = 0; | |
entries_index = 0; | |
} | |
} | |
char *File::getPath() { | |
return file_path; | |
} | |
char *File::getName() { | |
return file_name; | |
} | |
File *File::getParent() { | |
return parent; | |
} | |
bool File::exists() { | |
return created; | |
} | |
bool File::isFile() { | |
return !isDir; | |
} | |
bool File::isDirectory() { | |
return isDir; | |
} | |
File *File::getChild(char *name) { | |
if (!isDir) { | |
std::cout << "[Error: cannot get child of non-directory" << file_path << "]\n"; | |
return nullptr; | |
} | |
std::cout << "Getting child " << name << " from " << file_path << "\n"; | |
char *fpath = (char*) malloc(250); | |
strcpy(fpath, file_path); | |
strcat(fpath, name); | |
char *fname = (char*)malloc(strlen(name+1)); | |
strcpy(fname, name); | |
for (int i = 0; i < entries_index; i++) { | |
if (strcmp(entries[i]->name, name) == 0) { | |
return new File(fs, this, fname, fpath, entries[i]->inode, fs->getInode(entries[i]->inode), false); | |
} | |
} | |
return new File(fs, this, fname, fpath, -1, nullptr, false); | |
} | |
File *File::getChildDir(char *name) { | |
if (!isDir) { | |
std::cout << "[Error: cannot get child of non-directory" << file_path << "]\n"; | |
return nullptr; | |
} | |
// TODO needs to call open | |
std::cout << "Getting child directory " << name << " from " << file_path << "\n"; | |
char *fpath = (char*) malloc(250); | |
strcpy(fpath, file_path); | |
strcat(fpath, name); | |
strcat(fpath, "/"); | |
char *fname = (char*) malloc(strlen(name + 1)); | |
strcpy(fname, name); | |
for (int i = 0; i < entries_index; i++) { | |
if (strcmp(entries[i]->name, name) == 0) { | |
return new File(fs, this, fname, fpath, entries[i]->inode, fs->getInode(entries[i]->inode), true); | |
} | |
} | |
return new File(fs, this, fname, fpath, -1, nullptr, true); | |
} | |
DirectoryEntry **File::getDirectoryContents() { | |
return entries; | |
} | |
void File::create() { | |
if (isDir) { | |
std::cout << "Use mkdir instead\n"; | |
return; | |
} | |
if (created) { | |
std::cout << "File already created\n"; | |
return; | |
} | |
created = true; | |
inode_number = fs->createInode(); | |
std::cout << "Creating new file '" << file_path << "' " << inode_number << " \n"; | |
inode = fs->getInode(inode_number); | |
inode->file_size = 0; | |
inode->file_type = FileType::FILE; | |
parent->addFile(this); | |
} | |
void File::addFile(File *child) { | |
if (!isDir) { | |
std::cout << "Can only add files to directories\n"; | |
return; | |
} | |
std::cout << "Adding file " << child->file_path << " to directory " << file_path << "\n"; | |
DirectoryEntry *entry = new DirectoryEntry(child->inode_number, child->file_name); | |
entries[entries_index++] = entry; | |
BlockCacheEntry *block = fs->getBlock(inode->blocks[0]); | |
std::cout << "Saving directory contents of " << file_path << " to block " << inode->blocks[0] << "\n"; | |
block->modified = true; | |
for (int i = 0; i < 16; i++) { | |
if (i >= entries_index) { | |
block->block[i * 32] = (unsigned char) 0xFF; | |
} else { | |
block->block[i * 32] = entries[i]->inode; | |
strncpy((char*)(block->block + i * 32 + 1), entries[i]->name, 31); | |
} | |
} | |
} | |
void File::seek(int pos) { | |
seek_pos = pos; | |
std::cout << "Seeking file " << file_path << " to position " << pos << "\n"; | |
} | |
void File::write(char *src, int len) { | |
std::cout << "Writing " << len << " bytes to " << file_path << " at position " << seek_pos << "\n"; | |
int remaining = len; | |
int offset = 0; | |
while (remaining > 0) { | |
int block_pos = seek_pos / 512; | |
BlockCacheEntry *block = nullptr; | |
if (inode->blocks[block_pos] == 0) { | |
block = fs->allocateBlock(); | |
inode->blocks[block_pos] = block->number; | |
} else { | |
block = fs->getBlock(inode->blocks[block_pos]); | |
} | |
int subpos = seek_pos % 512; | |
int sublen = 512 - subpos; | |
if (remaining < sublen) { | |
sublen = remaining; | |
} | |
memcpy(block->block + subpos, src + offset, sublen); | |
block->modified = true; | |
seek_pos += sublen; | |
remaining -= sublen; | |
offset += sublen; | |
} | |
if (seek_pos > inode->file_size) { | |
inode->file_size = seek_pos; | |
std::cout << "new file size is " << inode->file_size << "\n"; | |
} | |
} | |
int File::read(char *dest, int len) { | |
if (seek_pos + len >= inode->file_size) { | |
len = inode->file_size - seek_pos; | |
} | |
std::cout << "Reading " << len << " bytes from file " << file_path << " at position " << seek_pos << "\n"; | |
int remaining = len; | |
int offset = 0; | |
while (remaining > 0) { | |
int block_pos = seek_pos / 512; | |
BlockCacheEntry *block = nullptr; | |
if (inode->blocks[block_pos] == 0) { | |
block = fs->allocateBlock(); | |
inode->blocks[block_pos] = block->number; | |
} else { | |
block = fs->getBlock(inode->blocks[block_pos]); | |
} | |
int subpos = seek_pos % 512; | |
int sublen = 512 - subpos; | |
if (remaining < sublen) { | |
sublen = remaining; | |
} | |
memcpy(dest + offset, block->block + subpos, sublen); | |
seek_pos += sublen; | |
offset += sublen; | |
remaining -= sublen; | |
} | |
return len; | |
} | |
void File::mkdir() { | |
if (!isDir) { | |
std::cout << "Cannot make a directory in a file\n"; | |
return; | |
} | |
if (created) { | |
std::cout << "Directory already created\n"; | |
return; | |
} | |
created = true; | |
inode_number = fs->createInode(); | |
std::cout << "Creating new dir '" << file_path << "' " << inode_number << " \n"; | |
inode = fs->getInode(inode_number); | |
inode->file_size = 512; | |
inode->file_type = FileType::DIR; | |
parent->addFile(this); | |
entries = (DirectoryEntry**) malloc(sizeof(DirectoryEntry*) * 32); | |
entries_size = 32; | |
entries_index = 0; | |
DirectoryEntry *self_dir = new DirectoryEntry(inode_number, "."); | |
DirectoryEntry *parent_dir = new DirectoryEntry(parent->inode_number, ".."); | |
entries[entries_index++] = self_dir; | |
entries[entries_index++] = parent_dir; | |
BlockCacheEntry *data = fs->allocateBlock(); | |
inode->blocks[0] = data->number; | |
std::cout << "Saving directory contents of " << file_path << " to block " << inode->blocks[0] << "\n"; | |
data->modified = true; | |
for (int i = 0; i < 16; i++) { | |
if (i >= entries_index) { | |
data->block[i * 32] = (unsigned char) 0xFF; | |
} else { | |
data->block[i * 32] = entries[i]->inode; | |
strncpy((char*) (data->block + i * 32 + 1), entries[i]->name, 31); | |
} | |
} | |
} | |
void File::remove() { | |
if (parent == nullptr) { | |
std::cout << "Cannot delete the root directory\n"; | |
} | |
if (isDir) { | |
std::cout << "Deleting directory " << file_path << "\n"; | |
for (int i = 0; i < entries_index; i++) { | |
DirectoryEntry *entry = entries[i]; | |
inode_t *child_inode = fs->getInode(entry->inode); | |
if (child_inode->file_type == FileType::DIR) { | |
File *child_dir = getChildDir(entry->name); | |
child_dir->remove(); | |
} else { | |
File *child = getChild(entry->name); | |
child->remove(); | |
} | |
} | |
} else { | |
std::cout << "Deleting file " << file_path << "\n"; | |
} | |
parent->removeFile(inode_number); | |
for (int i = 0; i < 10; i++) { | |
if (inode->blocks[i] != 0) { | |
fs->releaseBlock(inode->blocks[i]); | |
} | |
} | |
fs->releaseInode(inode_number); | |
} | |
void File::removeFile(int inode_num) { | |
if (!isDir) { | |
std::cout << "Can only remove files from directories\n"; | |
return; | |
} | |
bool found = false; | |
DirectoryEntry *found_entry = nullptr; | |
for (int i = 0; i < entries_index; i++) { | |
if (found) { | |
entries[i - 1] = entries[i]; | |
} else { | |
if (entries[i]->inode == inode_num) { | |
found = true; | |
found_entry = entries[i]; | |
} | |
} | |
} | |
if (found_entry == nullptr) { | |
std::cout << "File with inode " << inode_num << " not found in directory " << file_path << "\n"; | |
return; | |
} | |
entries_index--; | |
delete found_entry; | |
BlockCacheEntry *block = fs->getBlock(inode->blocks[0]); | |
std::cout << "Saving directory contents of " << file_path << " to block " << inode->blocks[0] << "\n"; | |
block->modified = true; | |
for (int i = 0; i < 16; i++) { | |
if (i >= entries_index) { | |
block->block[i * 32] = (unsigned char) 0xFF; | |
memset(block->block + i * 32 + 1, 0, 31); | |
} else { | |
block->block[i * 32] = entries[i]->inode; | |
strncpy((char*) (block->block + i * 32 + 1), entries[i]->name, 31); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdio> | |
namespace Filesystem { | |
#pragma pack(push, 1) | |
typedef struct superblock_t { | |
int type; // the file system type specifier (always the string LLFS) | |
int file_count; // the count of all files in the system | |
int inode_count; // the count of all allocated inodes in the system | |
} superblock_t; | |
typedef struct inode_t { | |
int file_size; // the size of the file in bytes | |
int file_type; // the file type | |
short blocks[10]; // the first 10 block refs | |
short single_indirect; // an inode ref containing refs to 16 more inodes each containing 16 block refs | |
short double_indirect; // two layers of indirection above ^ | |
} inode_t; | |
#pragma pack(pop) | |
enum FileType { | |
FILE, | |
DIR, | |
LINK | |
}; | |
class BlockCacheEntry { | |
public: | |
BlockCacheEntry(int number, char *block) : number(number), block(block), modified(false) {} | |
unsigned int number; | |
char *block; | |
bool modified; | |
}; | |
class DirectoryEntry { | |
public: | |
DirectoryEntry(int inode, char *name) : inode(inode), name(name) {} | |
unsigned char inode; | |
char *name; | |
}; | |
class LLFS; | |
class File { | |
public: | |
File(LLFS *fs, File *parent, char *name, char *path, int inode_number, inode_t *inode, bool isDir); | |
char *getPath(); | |
char *getName(); | |
File *getParent(); | |
bool exists(); | |
bool isFile(); | |
bool isDirectory(); | |
void mkdir(); | |
void create(); | |
void remove(); | |
void seek(int position); | |
int read(char *dest, int length); | |
void write(char *src, int length); | |
File *getChild(char *name); | |
File *getChildDir(char *name); | |
DirectoryEntry **getDirectoryContents(); | |
private: | |
LLFS *fs; | |
bool isDir; | |
bool created; | |
File *parent; | |
char *file_name; | |
char *file_path; | |
inode_t *inode; | |
unsigned int inode_number; | |
int seek_pos; | |
DirectoryEntry **entries; | |
int entries_size; | |
int entries_index; | |
void addFile(File *child); | |
void removeFile(int inode); | |
}; | |
class LLFS { | |
public: | |
LLFS(std::FILE *disk); | |
//~LLFS(); | |
File *open(char *path); | |
void close(File *file); | |
void sync(); | |
std::FILE *getDisk(); | |
friend class File; | |
private: | |
std::FILE *disk; | |
superblock_t *superblock; | |
char *free_blocks; | |
char *free_inodes; | |
char *inode_block_cache[32]; | |
BlockCacheEntry **static_cache; | |
int static_cache_size; | |
int static_cache_index; | |
BlockCacheEntry **dynamic_cache; | |
int dynamic_cache_size; | |
int dynamic_cache_index; | |
File *root; | |
File **open_files; | |
int open_files_size; | |
int open_files_index; | |
inode_t *getInode(int number); | |
unsigned int createInode(); | |
BlockCacheEntry *getBlock(int number); | |
BlockCacheEntry *allocateBlock(); | |
void releaseBlock(int block); | |
void releaseInode(int inode); | |
}; | |
void format(char *disk); | |
LLFS *mount(char *disk); | |
void unmount(LLFS *fs); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ hexdump vdisk | |
00000000: 4C 4C 46 53 01 00 00 00 - 03 00 00 00 00 00 00 00 |LLFS | | |
00000010: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
* | |
00000200: 00 E0 FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000210: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000220: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000230: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000240: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000250: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000260: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000270: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000280: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000290: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
000002a0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
000002b0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
000002c0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
000002d0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
000002e0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
000002f0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000300: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000310: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000320: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000330: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000340: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000350: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000360: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000370: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000380: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000390: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
000003a0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
000003b0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
000003c0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
000003d0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
000003e0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
000003f0: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF 7F | | | |
00000400: F8 FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000410: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF | | | |
00000420: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
* | |
00001400: 00 2E 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | . | | |
00001410: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001420: 00 2E 2E 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | .. | | |
00001430: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001440: 01 74 6D 70 00 00 00 00 - 00 00 00 00 00 00 00 00 | tmp | | |
00001450: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001460: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001470: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001480: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001490: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000014a0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000014b0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000014c0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000014d0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000014e0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000014f0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001500: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001510: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001520: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001530: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001540: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001550: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001560: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001570: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001580: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001590: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000015a0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000015b0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000015c0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000015d0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000015e0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000015f0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001600: 01 2E 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | . | | |
00001610: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001620: 00 2E 2E 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | .. | | |
00001630: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001640: 02 74 65 73 74 00 00 00 - 00 00 00 00 00 00 00 00 | test | | |
00001650: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001660: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001670: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001680: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001690: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000016a0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000016b0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000016c0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000016d0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000016e0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000016f0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001700: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001710: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001720: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001730: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001740: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001750: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001760: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001770: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001780: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001790: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000017a0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000017b0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000017c0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000017d0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000017e0: FF 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
000017f0: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
00001800: 48 65 6C 6C 6F 20 57 6F - 72 6C 64 21 00 00 00 00 |Hello World! | | |
00001810: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
* | |
0001fe00: 00 02 00 00 01 00 00 00 - 0D 0A 00 00 00 00 00 00 | | | |
0001fe10: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
0001fe20: 00 00 02 00 00 01 00 00 - 00 0B 00 00 00 00 00 00 | | | |
0001fe30: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
0001fe40: 00 0C 00 00 00 00 00 00 - 00 0C 00 00 00 00 00 00 | | | |
0001fe50: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | | | |
* | |
00200000: 00 - | | | |
00200001; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment