Compare commits

..

3 Commits

Author SHA1 Message Date
FactorialN
4577d85979 somewhat runs but apparently I/O is incorrect 2023-11-30 01:26:13 -08:00
FactorialN
00c6687466 changed unimplemented methods to -1 2023-11-29 19:23:32 -08:00
FactorialN
e377098fbc it now compiles and somewhat works 2023-11-29 19:01:08 -08:00
23 changed files with 1034 additions and 2111 deletions

View File

@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14)
include_directories(
# fischl include files
${CMAKE_CURRENT_SOURCE_DIR}/include
# ${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include
${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include
)
add_executable(fischl
@ -16,7 +16,8 @@ add_executable(fischl
lib/rawdisk.cpp
lib/fs/datablock_manager.cpp
lib/fs/fs_data_types.cpp
lib/fs/fs_file_io.cpp
lib/fs/fs_resize.cpp
lib/fs/fs_read_write.cpp
lib/fs/fs.cpp
lib/fs/inode_manager.cpp
lib/files.cpp

View File

@ -19,29 +19,6 @@ cmake ..
make # cmake --build . is same
```
## mount and test
normal usage:
```bash
./fischl diskpath n -s mountpoint
```
diskpath must be provided following ./fischl
l/n must be provided following diskpath indicating whether to load the exisiting file system or create a new one.
for loading:
```bash
./fischl diskpath l -s mountpoint
```
-s is also required because our fs doesn't support multi-threading.
if the diskpath need to be accessed by root:
```bash
sudo ./fischl diskpath n -o allow_other -s mountpoint
```
for debugging:
```bash
sudo ./fischl diskpath n -o allow_other -d -s mountpoint
```
## run test
### add your own test file on test/CMakeList.txt
```

View File

@ -19,48 +19,18 @@ typedef struct treeNode {
FileNode *self_info; //self fileNode infromation
} TreeNode;
typedef struct RenameInfo {
FileNode *oldFileNode; // The file node being renamed.
FileNode *oldParentNode; // The parent directory of the file node being renamed.
FileNode *newParentNode; // The target parent directory where the file node will be moved.
char *newName; // The new name of the file node after the rename.
FileNode *newFileNode; // The new file node, if one already exists at the target location.
bool exchangeExist; // Flag to indicate if the rename should replace an existing file node.
} RenameInfo;
/*for root*/
TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode_Data *new_inode);
/*the to be added file in add_entry should be parent-child relationship with treenode, otherwise will wrong */
/*see Add_FindFiletest in dir_API.cpp*/
FileNode* fischl_add_entry_for_cache(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode);
int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode);
int fischl_rm_entry(TreeNode *parent, const char *fileName);
/*if want to use dir mode use the subdirectory treeNode pointer */
//e.g. FileNode *Dirnode = fischl_find_entry(); can see file inside with Dirnode->subdirectory
//e.g. go to the current Dirnode parent directory, use TreeNode *get_Dir_parent = Dirnode->subdirectory->parent;
FileNode *fischl_find_entry(Fs *fs, TreeNode *root, const char *path);
FileNode *fischl_find_entry(TreeNode *root, const char *path);
void freeTree(TreeNode *node);
/*for debug use*/
TreeNode *createDirectory(const char *dirName, TreeNode *parent, int hashSize);
TreeNode *find_parentPath(TreeNode *root, const char *path);
struct DirectoryEntry {
u_int64_t inode_number;
char file_name[256];
void serialize(char* buffer) {
u_int64_t t = inode_number;
for (int j = 0; j < 8; j++){
buffer[j] = t & (((u_int64_t)1<<(8))-1);
t >>= 8;
}
strcpy(buffer+8, file_name);
}
void deserialize(char* buffer) {
inode_number = 0;
for (int j = 0; j < 8; j++)
inode_number = inode_number | (((u_int64_t)(unsigned char)buffer[j])<<(8*j));
strcpy(file_name, buffer+8);
}
};
TreeNode *find_parentPath(TreeNode *root, const char *path);

View File

@ -1,6 +1,6 @@
#include <sys/types.h>
#include <fs.hpp>
#include <fuse.h>
#include "fuse_common.h"
#include "direntry.h"
class FilesOperation {
@ -8,44 +8,25 @@ class FilesOperation {
Fs *fs;
void create_dot_dotdot(INode_Data*, u_int64_t);
public:
public:
TreeNode *root_node;
FilesOperation(RawDisk&, Fs*);
//int read_datablock(const INode_Data& inode, u_int64_t index, char* buffer);
//int write_datablock(INode_Data& inode, u_int64_t index, char* buffer);
void initialize_rootinode();
void initialize(bool load);
void printbuffer(const char*,int);
void printDirectory(u_int64_t);
bool permission_check(int, INode_Data*);
bool permission_check_by_inode_num(int, u_int64_t);
INode_Data* create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode);
int insert_inode_to(u_int64_t parent_inode_number, const char* name, INode_Data *new_inode, bool check_replace);
void unlink_inode(u_int64_t inode_number);
u_int64_t disk_namei(const char* path);
u_int64_t namei(const char* path);
int fischl_mkdir(const char*, mode_t);
int fischl_mknod(const char*, mode_t, dev_t);//for special file
int fischl_access(const char* path, int mask);
int fischl_create(const char *, mode_t, struct fuse_file_info *);//for regular file
int fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi);
int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags);
int fischl_releasedir(const char* path, struct fuse_file_info *fi);
//int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags);
int fischl_unlink (const char *);
int fischl_opendir(const char* path, struct fuse_file_info* fi);
int fischl_rmdir(const char *);
int fischl_readlink(const char* path, char* buf, size_t size);
int fischl_symlink(const char* from, const char* to);
int fischl_link(const char* from, const char* to);
int fischl_rename(const char *path, const char *, unsigned int flags);
int fischl_truncate(const char *path, off_t, struct fuse_file_info *fi);
int fischl_chmod(const char *path, mode_t, struct fuse_file_info *fi);
int fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi);
int fischl_open (const char *, struct fuse_file_info *);//open file
int fischl_release (const char *, struct fuse_file_info *);//close file
int fischl_write(const char *, const char *, size_t, off_t, struct fuse_file_info *);
int fischl_read(const char *, char *, size_t, off_t, struct fuse_file_info *);
int fischl_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi);
int fischl_statfs(const char* path, struct statvfs* stbuf);
FileNode *fischl_load_entry(TreeNode *root, const char *path);
};
};

View File

@ -15,12 +15,20 @@ public:
Fs(RawDisk *disk);
~Fs();
int allocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num);
int deallocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num);
ssize_t read(INode_Data *inode_data, char buf[], size_t count, size_t offset);
ssize_t write(INode_Data *inode_data, const char buf[], size_t count,
ssize_t write(INode_Data *inode_data, char buf[], size_t count,
size_t offset);
int truncate(INode_Data *inode_data, off_t length);
ssize_t lseek_next_data(INode_Data *inode_data, size_t offset);
ssize_t lseek_next_hole(INode_Data *inode_data, size_t offset);
int sweep_inode_datablocks(INode_Data *inode_data,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op);
int sweep_datablocks(u_int64_t *block_num, int indirect_num,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op);
int format();
@ -36,13 +44,8 @@ public:
int save_free_list_head(u_int64_t new_free_list_head);
int save_inode_list_head(u_int64_t new_inode_list_head);
int sweep_inode_datablocks(INode_Data *inode_data,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op);
int sweep_datablocks(u_int64_t *block_num, int indirect_num,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op);
int allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num);
int deallocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num);
};
#endif

View File

@ -25,14 +25,12 @@ public:
u_int64_t inode_num;
#define NUMBER_OF_METADATA_BYTES \
(6 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t)))
(4 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t)))
struct INode_MetaData {
u_int64_t uid;
u_int64_t gid;
u_int64_t permissions;
u_int64_t size; // not yet implemented
u_int64_t access_time;
u_int64_t modification_time;
u_int32_t reference_count;
u_int32_t flags;
} metadata;
@ -41,10 +39,6 @@ public:
#define NUMBER_OF_DIRECT_BLOCKS \
(((INODE_SIZE - NUMBER_OF_METADATA_BYTES) / sizeof(u_int64_t)) - 3)
#define FILE_SIZE_MAX \
(IO_BLOCK_SIZE * (NUMBER_OF_DIRECT_BLOCKS + INDIRECT_BLOCKS + \
(INDIRECT_BLOCKS * INDIRECT_BLOCKS) + \
(INDIRECT_BLOCKS * INDIRECT_BLOCKS * INDIRECT_BLOCKS)))
u_int64_t single_indirect_block, double_indirect_block, triple_indirect_block;
u_int64_t direct_blocks[NUMBER_OF_DIRECT_BLOCKS];

View File

@ -2,7 +2,6 @@
#define FS_CONSTANTS_HPP
#include <algorithm>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/fs.h>
@ -12,11 +11,10 @@
#include <sys/ioctl.h>
#include <unistd.h>
#define IO_BLOCK_SIZE 4096
#define INDIRECT_BLOCKS 512
#define NUM_INODE_BLOCKS 262143
#define NUM_INODE_BLOCKS 1023
#define NUM_BLOCKS 2048
#define INODE_SIZE 512

82
include/fuse_common.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef FUSE_COMMON_H_
#define FUSE_COMMON_H_
#include <stdint.h>
#include <sys/types.h>
/**
* Information about an open file.
*
* File Handles are created by the open, opendir, and create methods and closed
* by the release and releasedir methods. Multiple file handles may be
* concurrently open for the same file. Generally, a client will create one
* file handle per file descriptor, though in some cases multiple file
* descriptors can share a single file handle.
*/
struct fuse_file_info {
/** Open flags. Available in open() and release() */
int flags;
/** In case of a write operation indicates if this was caused
by a delayed write from the page cache. If so, then the
context's pid, uid, and gid fields will not be valid, and
the *fh* value may not match the *fh* value that would
have been sent with the corresponding individual write
requests if write caching had been disabled. */
unsigned int writepage : 1;
/** Can be filled in by open/create, to use direct I/O on this file. */
unsigned int direct_io : 1;
/** Can be filled in by open and opendir. It signals the kernel that any
currently cached data (ie., data that the filesystem provided the
last time the file/directory was open) need not be invalidated when
the file/directory is closed. */
unsigned int keep_cache : 1;
/** Can be filled by open/create, to allow parallel direct writes on this
* file */
unsigned int parallel_direct_writes : 1;
/** Indicates a flush operation. Set in flush operation, also
maybe set in highlevel lock operation and lowlevel release
operation. */
unsigned int flush : 1;
/** Can be filled in by open, to indicate that the file is not
seekable. */
unsigned int nonseekable : 1;
/* Indicates that flock locks for this file should be
released. If set, lock_owner shall contain a valid value.
May only be set in ->release(). */
unsigned int flock_release : 1;
/** Can be filled in by opendir. It signals the kernel to
enable caching of entries returned by readdir(). Has no
effect when set in other contexts (in particular it does
nothing when set by open()). */
unsigned int cache_readdir : 1;
/** Can be filled in by open, to indicate that flush is not needed
on close. */
unsigned int noflush : 1;
/** Padding. Reserved for future use*/
unsigned int padding : 23;
unsigned int padding2 : 32;
/** File handle id. May be filled in by filesystem in create,
* open, and opendir(). Available in most other file operations on the
* same file handle. */
uint64_t fh;
/** Lock owner id. Available in locking operations and flush */
uint64_t lock_owner;
/** Requested poll events. Available in ->poll. Only set on kernels
which support it. If unsupported, this field is set to zero. */
uint32_t poll_events;
};
#endif /* FUSE_COMMON_H_ */

View File

@ -156,26 +156,6 @@ TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode_Da
return newDir;
}
FileNode* fischl_add_entry_for_cache(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode){
char *Name = strdup(fileName);
TreeNode *newDir = NULL;
/*If directory, malloc TreeNode, and then create filenode that belongs to Parent hash table content*/
if ((new_inode->metadata.permissions & S_IFMT) == S_IFDIR) {
newDir = (TreeNode *)malloc(sizeof(TreeNode));
newDir->dirName = Name;
newDir->contents = createHashTable(20);//hasSize define 20
newDir->parent = parent;
}
FileNode *newFile = insertHash(parent->contents, Name, newDir); //newDir == NULL indicates it's a file
//assign INode *new_inode metadata to data member in FileNode structure
newFile->permissions = new_inode->metadata.permissions;
newFile->inode_number = new_inode_number;
//Diretory have its own file information, that is . here
if(newDir != NULL)
newDir->self_info = newFile;
return newFile;
}
int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode){
char *Name = strdup(fileName);
TreeNode *newDir = NULL;
@ -211,15 +191,13 @@ int fischl_rm_entry(TreeNode *parent, const char *fileName) {
}
FileNode *fischl_find_entry(Fs *fs, TreeNode *root, const char *path){
FileNode *fischl_find_entry(TreeNode *root, const char *path){
//support . and .. function
char *pathCopy = strdup(path);
char *segment = strtok(pathCopy, "/");
TreeNode *current = root;
FileNode *file = NULL;
printf("FINDING %s %s %llu\n", path, segment, current->self_info->inode_number);
while (segment != NULL && current != NULL) {
if (strcmp(segment, "..") == 0) {
// Move up to the parent directory
@ -236,29 +214,8 @@ FileNode *fischl_find_entry(Fs *fs, TreeNode *root, const char *path){
}
else{
file = lookupHash(current->contents, segment);
if (file == NULL) {
// find on disk whether this exists
INode_Data inode;
inode.inode_num = current->self_info->inode_number;
fs->inode_manager->load_inode(&inode);
char buffer[IO_BLOCK_SIZE] = {0};
for (u_int64_t idx=0; idx<inode.metadata.size/IO_BLOCK_SIZE; idx++) {
fs->read(&inode, buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE);
DirectoryEntry ent;
for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){
ent.deserialize(buffer+i);
//printf("WARNING:%d %llu %llu %s %s\n",__LINE__,inode.inode_num, ent.inode_number, ent.file_name, segment);
if (ent.inode_number && strcmp(ent.file_name, segment)==0) {
file = fischl_add_entry_for_cache(current, ent.inode_number, ent.file_name, &inode);
//printf("DONE !! %llu\n", file->inode_number);
break;
}
}
}
}
if (file != NULL && file->subdirectory == NULL) {
free(pathCopy);
printf("FOUND !! %llu\n", file->inode_number);
return file; //File found
//return current; return filenode
}

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,6 @@ static struct options {
Fs *fs;
FilesOperation *fsop;
int show_help;
bool load;
} options;
#define OPTION(t, p) \
@ -34,9 +33,9 @@ static const struct fuse_opt option_spec[] = {
};
void* fischl_init(struct fuse_conn_info *conn, struct fuse_config *cfg) {
cfg->use_ino = 1;
conn->want &= ~FUSE_CAP_ATOMIC_O_TRUNC;
options.fsop->initialize(options.load);
options.fsop->initialize_rootinode();
perror("FUSE INITIALIZATION RUNNING");
}
int fischl_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
@ -49,27 +48,48 @@ void fischl_destroy(void* private_data) {
}
static int fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) {
return options.fsop->fischl_getattr(path, stbuf, fi);
(void) fi;
int res = 0;
u_int64_t fh = options.fsop->namei(path);
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (fh != -1) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
// TO DO: make this the correct value
stbuf->st_size = 3;
} else
res = -ENOENT;
return res;
}
static int fischl_access(const char* path, int mask) {
return options.fsop->fischl_access(path, mask);
// return 0 when access is allowed
return 0;
}
static int fischl_readlink(const char* path, char* buf, size_t size) {
return options.fsop->fischl_readlink(path, buf, size);
return -1;
}
static int fischl_opendir(const char* path, struct fuse_file_info* fi) {
return options.fsop->fischl_opendir(path, fi);
perror(path);
return -1;
}
static int fischl_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t ft, struct fuse_file_info *fi, enum fuse_readdir_flags flg) {
return options.fsop->fischl_readdir(path, buf, filler, ft, fi, flg);
static int fischl_readdir(const char *path, void *buf, fuse_fill_dir_t t, off_t ft, struct fuse_file_info *fi, enum fuse_readdir_flags) {
return -1;
}
static int fischl_mknod(const char* path, mode_t mode, dev_t rdev) {
return options.fsop->fischl_mknod(path, mode, rdev);
return -1;
}
static int fischl_mkdir(const char *path, mode_t mode) {
@ -81,35 +101,35 @@ static int fischl_unlink(const char* path) {
}
static int fischl_rmdir(const char* path) {
return options.fsop->fischl_rmdir(path);
return -1;
}
static int fischl_symlink(const char* from, const char* to) {
return options.fsop->fischl_symlink(from, to);
static int fischl_symlink(const char* to, const char* from) {
return -1;
}
static int fischl_rename(const char *path, const char *new_name, unsigned int flags) {
return options.fsop->fischl_rename(path, new_name, flags);
static int fischl_rename(const char *path, const char *, unsigned int flags) {
return -1;
}
static int fischl_link(const char* from, const char* to) {
return options.fsop->fischl_link(from, to);
return -1;
}
static int fischl_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) {
return options.fsop->fischl_chmod(path, mode, fi);
static int fischl_chmod(const char *path, mode_t, struct fuse_file_info *fi) {
return -1;
}
static int fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi) {
return options.fsop->fischl_chown(path, uid, gid, fi);
static int fischl_chown(const char *path, uid_t, gid_t, struct fuse_file_info *fi) {
return -1;
}
static int fischl_truncate(const char *path, off_t offset, struct fuse_file_info *fi) {
return options.fsop->fischl_truncate(path, offset, fi);
static int fischl_truncate(const char *path, off_t, struct fuse_file_info *fi) {
return -1;
}
static int fischl_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi) {
return options.fsop->fischl_utimens(path, tv, fi);
return -1;
}
static int fischl_open(const char *path, struct fuse_file_info *fi) {
@ -121,11 +141,11 @@ static int fischl_read(const char* path, char *buf, size_t size, off_t offset, s
}
static int fischl_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
return options.fsop->fischl_write(path, buf, size, offset, fi);
return options.fsop->fischl_write(path, buf, size, offset, fi);
}
static int fischl_statfs(const char* path, struct statvfs* stbuf) {
return options.fsop->fischl_statfs(path, stbuf);
return -1;
}
static int fischl_release(const char* path, struct fuse_file_info *fi) {
@ -133,7 +153,19 @@ static int fischl_release(const char* path, struct fuse_file_info *fi) {
}
static int fischl_releasedir(const char* path, struct fuse_file_info *fi) {
return options.fsop->fischl_releasedir(path, fi);
return -1;
}
static int fischl_bmap(const char* path, size_t blocksize, uint64_t* blockno) {
return -1;
}
static int fischl_ioctl(const char* path, int cmd, void* arg, struct fuse_file_info* fi, unsigned int flags, void* data) {
return -1;
}
static int fischl_poll(const char* path, struct fuse_file_info* fi, struct fuse_pollhandle* ph, unsigned* reventsp){
return -1;
}
@ -173,9 +205,9 @@ static const struct fuse_operations fischl_oper = {
.access = fischl_access,
.create = fischl_create,
.utimens = fischl_utimens,
//.bmap = fischl_bmap,
//.ioctl = fischl_ioctl,
//.poll = fischl_poll,
.bmap = fischl_bmap,
.ioctl = fischl_ioctl,
.poll = fischl_poll,
};
static void show_help(const char *progname)
@ -193,104 +225,16 @@ static void show_help(const char *progname)
int fischl(int argc, char *argv[])
{
int ret;
if(argc < 3){
printf("WRONG ARGUMENTS\n");
return 0;
}
std::swap(argv[0], argv[1]);
std::swap(argv[1], argv[2]);
struct fuse_args args = FUSE_ARGS_INIT(argc-2, argv+2);
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
srand(time(NULL)); // Seed the random number generator
//const char* d = (argc < 2) ? "/dev/vdc" : argv[1];
//setupTestDirectory(&options.root);
if(strcmp(argv[0], "fake")==0){
options.H = new FakeRawDisk(27648);
}
else{
options.H = new RealRawDisk(argv[0]);
char zero_es[IO_BLOCK_SIZE] = {0};
/*printf("zeroed\n");
for (int i = 0; i < 200000; i++){
options.H->write_block(i, zero_es);
}*/
}
if(strcmp(argv[1], "l")==0){
options.load = true;
}
else if(strcmp(argv[1], "n")==0){
options.load = false;
}
else{
printf("WRONG l/n ARGUMENTS\n");
return 0;
}
options.H = new FakeRawDisk(21504);
options.fs = new Fs(options.H);
if(!options.load){
printf("FORMAT %d\n", options.fs->format());
}
options.fs->format();
options.fsop = new FilesOperation(*options.H, options.fs);
/*INode_Data inode_data;
options.fs->inode_manager->new_inode(1, 2, 3, &inode_data);
int buf_size = 100000;
int seg_size = 10;
char buf[buf_size];
int res;
int num = 1;
for (u_int64_t i = 0; i < 30 * 1024 * 1024;) {
for (int j = 0; j < buf_size;) {
j += sprintf(&buf[j], "%010d\n", ++num);
}
res = options.fs->write(&inode_data, buf, buf_size, i);
if (res < buf_size)
printf("ERR: %d %d\n", res, i);
i += res;
}
num = 1;
printf("done write\n");
char buf2[buf_size];
for (u_int64_t i = 0; i < 30 * 1024 * 1024;) {
for (int j = 0; j < buf_size;) {
j += sprintf(&buf[j], "%010d\n", ++num);
}
res = options.fs->read(&inode_data, buf2, buf_size, i);
if (res < buf_size)
printf("ERR2: %d %d\n", res, i);
i += res;
for (int j = 0; j < res; ++j) {
if (buf[j] != buf2[j])
printf("err err err: %d %d", buf[j], i);
}
}
printf("done read\n");
num = 1;
for (u_int64_t i = 0; i < 30 * 1024 * 1024;) {
for (int j = 0; j < buf_size;) {
j += sprintf(&buf[j], "%010d\n", ++num);
}
res = options.fs->read(&inode_data, buf2, buf_size, i);
if (res < buf_size)
printf("ERR2: %d %d\n", res, i);
i += res;
for (int j = 0; j < res; ++j) {
if (buf[j] != buf2[j])
printf("err err err: %d %d", buf[j], i);
}
}
printf("done read2\n");*/
/* Parse options */

View File

@ -1,7 +1,7 @@
#include "fs.hpp"
DataBlock_Manager::DataBlock_Manager(Fs *fs, u_int64_t block_segment_start,
u_int64_t block_segment_end)
u_int64_t block_segment_end)
: fs(fs), block_segment_start(block_segment_start),
block_segment_end(block_segment_end) {}
@ -52,24 +52,16 @@ int DataBlock_Manager_Bitmap::new_datablock(u_int64_t *block_num) {
char zero_buf[IO_BLOCK_SIZE] = {0};
if (bitmap_block_num < block_segment_start ||
bitmap_block_num >= block_segment_end) {
perror("Error with new_datablock freelist head\n");
bitmap_block_num >= block_segment_end)
return -1;
}
if ((err = fs->disk->read_block(bitmap_block_num, bitmap.buf)) < 0)
return err;
// if (bitmap.get_next_node() == fs->superblock.free_list_head)
// printf("WARNING: ON LAST BITMAP "
// "BLOCK!\n");
u_int64_t relative_block_num = bitmap.claim_relative_block();
if (relative_block_num == 0) {
errno = ENOSPC;
if (relative_block_num == 0)
return -1;
}
u_int64_t block_num_ = relative_block_num + bitmap_block_num;
@ -130,7 +122,6 @@ int DataBlock_Manager_Bitmap::format() {
char buf[IO_BLOCK_SIZE] = {0};
int err;
u_int64_t i = block_segment_start;
write_u64(i, buf);
for (; i <= block_segment_end - (2 * bitmap_region_size);
i += bitmap_region_size) {
write_u64(i + bitmap_region_size, buf);

View File

@ -1,13 +1,10 @@
#include "fs.hpp"
#include <assert.h>
Fs::Fs(RawDisk *disk) : disk(disk) {
assert((disk->diskSize / IO_BLOCK_SIZE) >
2 + NUM_INODE_BLOCKS + DATABLOCKS_PER_BITMAP_BLOCK);
superblock = SuperBlock_Data();
inode_manager = new INode_Manager_Freelist(this, 1, 1 + NUM_INODE_BLOCKS);
datablock_manager = new DataBlock_Manager_Bitmap(
this, 1 + NUM_INODE_BLOCKS, disk->diskSize / IO_BLOCK_SIZE);
datablock_manager =
new DataBlock_Manager_Bitmap(this, 1 + NUM_INODE_BLOCKS, disk->diskSize/IO_BLOCK_SIZE);
};
Fs::~Fs() {

View File

@ -1,5 +1,4 @@
#include "fs.hpp"
#include <time.h>
template <typename T> T write_int(T num, char buf[]) {
size_t i = 0;
@ -51,15 +50,11 @@ void SuperBlock_Data::deserialize(char buf[]) {
}
INode_Data::INode_Data(u_int64_t inode_num) : inode_num(inode_num) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
metadata.uid = -1;
metadata.gid = -1;
metadata.permissions = -1;
metadata.size = 0;
metadata.access_time = (u_int64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec;
metadata.modification_time = (u_int64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec;
metadata.reference_count = 1;
metadata.reference_count = 0;
single_indirect_block = double_indirect_block = triple_indirect_block = 0;
@ -73,8 +68,6 @@ size_t INode_Data::serialize_metadata(char buf[]) {
i += write_u64(metadata.gid, &buf[i]);
i += write_u64(metadata.permissions, &buf[i]);
i += write_u64(metadata.size, &buf[i]);
i += write_u64(metadata.access_time, &buf[i]);
i += write_u64(metadata.modification_time, &buf[i]);
i += write_u32(metadata.reference_count, &buf[i]);
i += write_u32(metadata.flags, &buf[i]);
return i;
@ -86,8 +79,6 @@ size_t INode_Data::deserialize_metadata(char buf[]) {
i += read_u64(&metadata.gid, &buf[i]);
i += read_u64(&metadata.permissions, &buf[i]);
i += read_u64(&metadata.size, &buf[i]);
i += read_u64(&metadata.access_time, &buf[i]);
i += read_u64(&metadata.modification_time, &buf[i]);
i += read_u32(&metadata.reference_count, &buf[i]);
i += read_u32(&metadata.flags, &buf[i]);
return i;

View File

@ -1,418 +0,0 @@
#include "fs.hpp"
class DatablockOperation {
public:
DatablockOperation(int (*_skip)(DatablockOperation *, u_int64_t) = nullptr)
: skip(_skip) {}
size_t count;
size_t offset;
size_t bytes_completed;
Fs *fs;
virtual int operation(u_int64_t block_num, bool *delete_block) = 0;
int (*skip)(DatablockOperation *, u_int64_t);
};
int default_skip_func(DatablockOperation *this_op, u_int64_t num_blocks) {
this_op->bytes_completed += (num_blocks * IO_BLOCK_SIZE) - this_op->offset;
this_op->offset = 0;
if (this_op->bytes_completed >= this_op->count)
return 0;
return 1;
}
int truncate_skip_func(DatablockOperation *this_op, u_int64_t num_blocks) {
this_op->offset = 0;
return 1;
}
int Fs::sweep_inode_datablocks(INode_Data *inode_data,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op) {
int result;
// printf("SWEEP %llu %llu %llu\n", inode_data->inode_num,
// inode_data->single_indirect_block, inode_data->double_indirect_block);
u_int64_t start_index = start_block_index;
for (size_t i = start_index; i < NUMBER_OF_DIRECT_BLOCKS; ++i) {
if ((result = sweep_datablocks(&(inode_data->direct_blocks[i]), 0, 0,
allocate, op)) <= 0)
return result;
start_index = NUMBER_OF_DIRECT_BLOCKS;
}
start_index -= NUMBER_OF_DIRECT_BLOCKS;
if (start_index < INDIRECT_BLOCKS) {
if ((result = sweep_datablocks(&(inode_data->single_indirect_block), 1,
start_index, allocate, op)) <= 0)
return result;
start_index = INDIRECT_BLOCKS;
}
start_index -= INDIRECT_BLOCKS;
if (start_index < INDIRECT_BLOCKS * INDIRECT_BLOCKS) {
if ((result = sweep_datablocks(&(inode_data->double_indirect_block), 2,
start_index, allocate, op)) <= 0)
return result;
start_index = INDIRECT_BLOCKS * INDIRECT_BLOCKS;
}
start_index -= INDIRECT_BLOCKS * INDIRECT_BLOCKS;
if (start_index <
(u_int64_t)INDIRECT_BLOCKS * INDIRECT_BLOCKS * INDIRECT_BLOCKS) {
if ((result = sweep_datablocks(&(inode_data->triple_indirect_block), 3,
start_index, allocate, op)) <= 0)
return result;
}
return 1;
}
// This can simply be made non recursive by copy pasting - it is just
// written this way as a proof of concept
int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op) {
char buf[IO_BLOCK_SIZE];
int err;
int result = -1;
u_int64_t num_blocks_indirect;
u_int64_t num_blocks = 1;
for (int i = 0; i < indirect_num; ++i) {
num_blocks_indirect = num_blocks;
num_blocks *= INDIRECT_BLOCKS;
}
if ((*block_num) == 0) {
if (allocate) {
if ((err = datablock_manager->new_datablock(block_num)) < 0)
return err;
} else if (op->skip != nullptr) {
return (*(op->skip))(op, num_blocks);
}
}
// if((*block_num)>30000000000000LL)printf("DIES 1 %llu %d %llu\n",
// *block_num, indirect_num, start_block_index);
if (indirect_num == 0) {
bool delete_block = false;
if ((result = op->operation(*block_num, &delete_block)) < 0)
return result;
if (delete_block) {
if ((err = datablock_manager->free_datablock(*block_num)) < 0)
return err;
(*block_num) = 0;
}
return result;
}
if ((*block_num) == 0) {
memset(buf, 0, sizeof(buf));
} else {
if ((err = disk->read_block(*block_num, buf)) < 0)
return err;
}
u_int64_t this_layer_start_index = start_block_index / num_blocks_indirect;
u_int64_t next_layer_start_index =
start_block_index - (num_blocks_indirect * this_layer_start_index);
u_int64_t temp;
u_int64_t next_block_num;
bool modified = false;
for (size_t i = this_layer_start_index * sizeof(u_int64_t); i < IO_BLOCK_SIZE;
i += sizeof(u_int64_t)) {
read_u64(&temp, &buf[i]);
next_block_num = temp;
if ((result = sweep_datablocks(&next_block_num, indirect_num - 1,
next_layer_start_index, allocate, op)) < 0)
return result;
if (next_block_num != temp) {
write_u64(next_block_num, &buf[i]);
modified = true;
}
if (result == 0)
break;
next_layer_start_index = 0;
}
if (modified) {
bool delete_block = true;
for (size_t i = 0; i < IO_BLOCK_SIZE; ++i)
if (buf[i] != 0) {
delete_block = false;
break;
}
if (delete_block) {
if ((err = datablock_manager->free_datablock(*block_num)) < 0)
return err;
(*block_num) = 0;
} else {
if ((err = disk->write_block(*block_num, buf)) < 0)
return err;
}
}
return result;
}
class ReadDatablockOperation : public DatablockOperation {
public:
char *buf;
ReadDatablockOperation() : DatablockOperation() {}
int operation(u_int64_t block_num, bool *delete_block) override {
char datablock_buf[IO_BLOCK_SIZE];
int err;
size_t read_size =
std::min(IO_BLOCK_SIZE - offset, count - bytes_completed);
if (block_num != 0) {
if ((block_num) > 3000000000000LL)
printf("DIES 2\n");
if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0)
return err;
memcpy(&buf[bytes_completed], &datablock_buf[offset], read_size);
} else {
memset(&buf[bytes_completed], 0, read_size);
}
offset = 0;
bytes_completed += read_size;
if (bytes_completed >= count)
return 0;
return 1;
}
};
class WriteDatablockOperation : public DatablockOperation {
public:
const char *buf;
WriteDatablockOperation() : DatablockOperation() {}
int operation(u_int64_t block_num, bool *delete_block) override {
char datablock_buf[IO_BLOCK_SIZE];
int err;
size_t write_size =
std::min(IO_BLOCK_SIZE - offset, count - bytes_completed);
if (write_size < IO_BLOCK_SIZE) {
if ((block_num) > 3000000000000LL)
printf("DIES 3\n");
if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0)
return err;
}
memcpy(&datablock_buf[offset], &buf[bytes_completed], write_size);
if ((err = fs->disk->write_block(block_num, datablock_buf)) < 0)
return err;
offset = 0;
bytes_completed += write_size;
if (bytes_completed >= count)
return 0;
return 1;
}
};
class TruncateDatablockOperation : public DatablockOperation {
public:
TruncateDatablockOperation() : DatablockOperation(truncate_skip_func) {}
int operation(u_int64_t block_num, bool *delete_block) override {
char datablock_buf[IO_BLOCK_SIZE];
int err;
if (offset == 0) {
(*delete_block) = true;
return 1;
}
if ((block_num) > 3000000000000LL)
printf("DIES 4\n");
if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0)
return err;
memset(&datablock_buf[offset], 0, IO_BLOCK_SIZE - offset);
if ((err = fs->disk->write_block(block_num, datablock_buf)) < 0)
return err;
offset = 0;
return 1;
}
};
class LseekNextDataDatablockOperation : public DatablockOperation {
public:
LseekNextDataDatablockOperation() : DatablockOperation(default_skip_func) {}
int operation(u_int64_t block_num, bool *delete_block) override { return 0; }
};
class LseekNextHoleDatablockOperation : public DatablockOperation {
public:
LseekNextHoleDatablockOperation() : DatablockOperation() {}
int operation(u_int64_t block_num, bool *delete_block) override {
if (block_num == 0)
return 0;
bytes_completed += (IO_BLOCK_SIZE)-offset;
offset = 0;
if (bytes_completed >= count)
return 0;
return 1;
}
};
ssize_t Fs::read(INode_Data *inode_data, char buf[], size_t count,
size_t offset) {
int err;
if (offset >= inode_data->metadata.size)
return 0;
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
ReadDatablockOperation op = ReadDatablockOperation();
op.offset = internal_offset;
op.buf = buf;
op.count = std::min(count, inode_data->metadata.size - offset);
op.bytes_completed = 0;
op.fs = this;
// printf("IN READ %llu %llu %llu\n", inode_data->inode_num,
// inode_data->single_indirect_block, inode_data->double_indirect_block);
if ((err = sweep_inode_datablocks(inode_data, start_block_index, false,
&op)) < 0)
return err;
return op.bytes_completed;
}
ssize_t Fs::write(INode_Data *inode_data, const char buf[], size_t count,
size_t offset) {
int err;
if (count + offset > FILE_SIZE_MAX) {
errno = EFBIG;
return -1;
}
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
WriteDatablockOperation op = WriteDatablockOperation();
op.offset = internal_offset;
op.buf = buf;
op.count = count;
op.bytes_completed = 0;
op.fs = this;
if ((err = sweep_inode_datablocks(inode_data, start_block_index, true, &op)) <
0)
return err;
inode_data->metadata.size =
std::max(offset + op.bytes_completed, inode_data->metadata.size);
return op.bytes_completed;
}
int Fs::truncate(INode_Data *inode_data, off_t length) {
int err;
if (length > FILE_SIZE_MAX) {
errno = EFBIG;
return -1;
}
if (length < 0) {
errno = EINVAL;
return -1;
}
u_int64_t start_block_index = length / IO_BLOCK_SIZE;
size_t internal_offset = length - (start_block_index * IO_BLOCK_SIZE);
TruncateDatablockOperation op = TruncateDatablockOperation();
op.offset = internal_offset;
op.fs = this;
if ((err = sweep_inode_datablocks(inode_data, start_block_index, false,
&op)) < 0)
return err;
inode_data->metadata.size = length;
return 0;
}
ssize_t Fs::lseek_next_data(INode_Data *inode_data, size_t offset) {
int err;
if (offset >= inode_data->metadata.size) {
errno = ENXIO;
return -1;
}
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
LseekNextDataDatablockOperation op = LseekNextDataDatablockOperation();
op.offset = internal_offset;
op.count = inode_data->metadata.size;
op.bytes_completed = offset;
op.fs = this;
if ((err = sweep_inode_datablocks(inode_data, start_block_index, false,
&op)) < 0)
return err;
if (op.bytes_completed >= inode_data->metadata.size) {
errno = ENXIO;
return -1;
}
return op.bytes_completed;
}
ssize_t Fs::lseek_next_hole(INode_Data *inode_data, size_t offset) {
int err;
if (offset >= inode_data->metadata.size) {
errno = ENXIO;
return -1;
}
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
LseekNextHoleDatablockOperation op = LseekNextHoleDatablockOperation();
op.offset = internal_offset;
op.count = inode_data->metadata.size;
op.bytes_completed = offset;
op.fs = this;
if ((err = sweep_inode_datablocks(inode_data, start_block_index, false,
&op)) < 0)
return err;
if (op.bytes_completed >= inode_data->metadata.size)
return inode_data->metadata.size;
return op.bytes_completed;
}

212
lib/fs/fs_read_write.cpp Normal file
View File

@ -0,0 +1,212 @@
#include "fs.hpp"
class DatablockOperation {
public:
char *buf;
size_t count;
size_t offset;
size_t bytes_completed;
RawDisk *disk;
virtual int operation(u_int64_t block_num) = 0;
};
int Fs::sweep_inode_datablocks(INode_Data *inode_data,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op) {
int result;
u_int64_t start_index = start_block_index;
for (size_t i = start_index; i < NUMBER_OF_DIRECT_BLOCKS; ++i) {
if ((result = sweep_datablocks(&(inode_data->direct_blocks[i]), 0, 0,
allocate, op)) <= 0)
return result;
start_index = NUMBER_OF_DIRECT_BLOCKS;
}
start_index -= NUMBER_OF_DIRECT_BLOCKS;
if (start_index < IO_BLOCK_SIZE) {
if ((result = sweep_datablocks(&(inode_data->single_indirect_block), 1,
start_index, allocate, op)) <= 0)
return result;
start_index = IO_BLOCK_SIZE;
}
start_index -= IO_BLOCK_SIZE;
if (start_index < IO_BLOCK_SIZE * IO_BLOCK_SIZE) {
if ((result = sweep_datablocks(&(inode_data->double_indirect_block), 2,
start_index, allocate, op)) <= 0)
return result;
start_index = IO_BLOCK_SIZE * IO_BLOCK_SIZE;
}
start_index -= IO_BLOCK_SIZE * IO_BLOCK_SIZE;
if (start_index < (u_int64_t)IO_BLOCK_SIZE * IO_BLOCK_SIZE * IO_BLOCK_SIZE) {
if ((result = sweep_datablocks(&(inode_data->triple_indirect_block), 3,
start_index, allocate, op)) <= 0)
return result;
}
return -1;
}
// This can simply be made non recursive by copy pasting - it is just
// written this way as a proof of concept
int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num,
u_int64_t start_block_index, bool allocate,
DatablockOperation *op) {
char buf[IO_BLOCK_SIZE];
int err;
int result = -1;
if (allocate && (*block_num) == 0)
if ((err = datablock_manager->new_datablock(block_num)) < 0)
return err;
if (indirect_num == 0)
return op->operation(*block_num);
if ((*block_num) == 0) {
memset(buf, 0, sizeof(buf));
} else {
if ((err = disk->read_block(*block_num, buf)) < 0)
return err;
}
u_int64_t indirect_block_size = 1;
for (int i = 1; i < indirect_num; ++i)
indirect_block_size *= IO_BLOCK_SIZE;
u_int64_t this_layer_start_index = start_block_index / indirect_block_size;
u_int64_t next_layer_start_index =
start_block_index - (indirect_block_size * this_layer_start_index);
u_int64_t temp;
u_int64_t next_block_num;
bool modified = false;
for (size_t i = this_layer_start_index * sizeof(u_int64_t); i < IO_BLOCK_SIZE;
i += sizeof(u_int64_t)) {
read_u64(&temp, &buf[i]);
next_block_num = temp;
if ((result = sweep_datablocks(&next_block_num, indirect_num - 1,
next_layer_start_index, allocate, op)) < 0)
return result;
if (next_block_num != temp) {
write_u64(next_block_num, &buf[i]);
modified = true;
}
if (result == 0)
break;
}
if (modified)
if ((err = disk->write_block(*block_num, buf)) < 0)
return err;
return result;
}
class ReadDatablockOperation : public DatablockOperation {
public:
int operation(u_int64_t block_num) override {
char datablock_buf[IO_BLOCK_SIZE];
int err;
// printf("PRINT: (%d) %d %d %d\n", block_num, count, offset,
// bytes_completed);
size_t read_size =
std::min(IO_BLOCK_SIZE - offset, count - bytes_completed);
if (block_num != 0) {
if ((err = disk->read_block(block_num, datablock_buf)) < 0)
return err;
memcpy(&buf[bytes_completed], &datablock_buf[offset], read_size);
} else {
memset(&buf[bytes_completed], 0, read_size);
}
offset = 0;
bytes_completed += read_size;
if (bytes_completed >= count)
return 0;
return 1;
}
};
class WriteDatablockOperation : public DatablockOperation {
public:
int operation(u_int64_t block_num) override {
char datablock_buf[IO_BLOCK_SIZE];
int err;
size_t write_size =
std::min(IO_BLOCK_SIZE - offset, count - bytes_completed);
if (write_size < IO_BLOCK_SIZE)
if ((err = disk->read_block(block_num, datablock_buf)) < 0)
return err;
memcpy(&datablock_buf[offset], &buf[bytes_completed], write_size);
if ((err = disk->write_block(block_num, datablock_buf)) < 0)
return err;
offset = 0;
bytes_completed += write_size;
if (bytes_completed >= count)
return 0;
return 1;
}
};
ssize_t Fs::read(INode_Data *inode_data, char buf[], size_t count,
size_t offset) {
int err;
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
ReadDatablockOperation op = ReadDatablockOperation();
op.offset = internal_offset;
op.buf = buf;
op.count = std::min(count, inode_data->metadata.size - offset);
op.bytes_completed = 0;
op.disk = disk;
if ((err = sweep_inode_datablocks(inode_data, start_block_index, false,
&op)) < 0)
return err;
return op.bytes_completed;
}
ssize_t Fs::write(INode_Data *inode_data, char buf[], size_t count,
size_t offset) {
int err;
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
WriteDatablockOperation op = WriteDatablockOperation();
op.offset = internal_offset;
op.buf = buf;
op.count = count;
op.bytes_completed = 0;
op.disk = disk;
if ((err = sweep_inode_datablocks(inode_data, start_block_index, true, &op)) <
0)
return err;
inode_data->metadata.size =
std::max(offset + op.bytes_completed, inode_data->metadata.size);
return op.bytes_completed;
}

141
lib/fs/fs_resize.cpp Normal file
View File

@ -0,0 +1,141 @@
#include "fs.hpp"
int Fs::allocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) {
int result;
for (size_t i = 0; i < NUMBER_OF_DIRECT_BLOCKS; ++i) {
result =
allocate_indirect(&(inode_data->direct_blocks[i]), 0, datablock_num);
if (result <= 0)
return result;
}
result =
allocate_indirect(&(inode_data->single_indirect_block), 1, datablock_num);
if (result <= 0)
return result;
result =
allocate_indirect(&(inode_data->double_indirect_block), 2, datablock_num);
if (result <= 0)
return result;
result =
allocate_indirect(&(inode_data->triple_indirect_block), 3, datablock_num);
if (result <= 0)
return result;
return -1;
}
// This can simply be made non recursive by copy pasting - it is just written
// this way as a proof of concept
int Fs::allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num) {
char buf[IO_BLOCK_SIZE];
int result;
if ((*storage) == 0) {
if ((result = datablock_manager->new_datablock(storage)) < 0)
return result;
if (n == 0) {
(*datablock_num) = (*storage);
return 0;
}
}
if (n == 0)
return 1;
u_int64_t temp;
if ((result = disk->read_block(*storage, buf)) < 0)
return result;
for (size_t i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) {
read_u64(&temp, &buf[i]);
result = allocate_indirect(&temp, n - 1, datablock_num);
if (result < 0)
return result;
if (result == 0) {
write_u64(temp, &buf[i]);
if ((result = disk->write_block(*storage, buf)) < 0)
return result;
return 0;
}
}
return 1;
}
int Fs::deallocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) {
int result;
result = deallocate_indirect(&(inode_data->triple_indirect_block), 3,
datablock_num);
if (result <= 0)
return result;
result = deallocate_indirect(&(inode_data->double_indirect_block), 2,
datablock_num);
if (result <= 0)
return result;
result = deallocate_indirect(&(inode_data->single_indirect_block), 1,
datablock_num);
if (result <= 0)
return result;
for (size_t i = NUMBER_OF_DIRECT_BLOCKS - 1; i >= 0; --i) {
result =
deallocate_indirect(&(inode_data->direct_blocks[i]), 0, datablock_num);
if (result <= 0)
return result;
}
return -1;
}
int Fs::deallocate_indirect(u_int64_t *storage, int n,
u_int64_t *datablock_num) {
char buf[IO_BLOCK_SIZE];
int result;
if (*storage == 0)
return 1;
if (n == 0) {
u_int64_t temp_datablock_num = (*storage);
if ((result = datablock_manager->free_datablock(*storage)) < 0)
return result;
(*datablock_num) = temp_datablock_num;
(*storage) = 0;
return 0;
}
u_int64_t temp;
if ((result = disk->read_block(*storage, buf)) < 0)
return result;
for (size_t i = IO_BLOCK_SIZE - sizeof(u_int64_t); i >= 0;
i -= sizeof(u_int64_t)) {
read_u64(&temp, &buf[i]);
result = deallocate_indirect(&temp, n - 1, datablock_num);
if (result < 0)
return result;
if (result == 0) {
if (i == 0 && temp == 0) {
if ((result = datablock_manager->free_datablock(*storage)) < 0)
return result;
(*storage) = 0;
} else {
write_u64(temp, &buf[i]);
if ((result = disk->write_block(*storage, buf)) < 0)
return result;
}
return 0;
}
}
return 1;
}

View File

@ -85,7 +85,5 @@ int main(int argc, char *argv[]) {
fischl(argc, argv);
return 0;
}

View File

@ -10,12 +10,12 @@ void RawDisk::print_block(u_int64_t block_number) {
return;
}
printf("\nBlock %lu:\n", block_number);
printf("\nBlock %llu:\n", block_number);
for (int i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) {
num = 0;
for (int j = 0; j < 8; j++)
num |= ((u_int64_t)(unsigned char)buf[i + j]) << (8 * j);
printf("%lu ", num);
printf("%llu ", num);
if ((i / sizeof(u_int64_t)) % nums_per_line == nums_per_line - 1)
printf("\n");
}
@ -43,14 +43,12 @@ RealRawDisk::RealRawDisk(const char *directory)
exit(1);
}
// diskSize = 27648 * IO_BLOCK_SIZE;
// Calculate the size in bytes
numSectors = diskSize / 512; // Assuming a sector size of 512 bytes
printf("====Initializing RawDisk====\n");
printf("Number of sectors: %lu\n", numSectors);
printf("Disk size (in bytes): %lu\n", diskSize);
printf("Number of sectors: %llu\n", numSectors);
printf("Disk size (in bytes): %llu\n", diskSize);
}
RealRawDisk::~RealRawDisk() {
@ -63,20 +61,14 @@ int RealRawDisk::read_block(u_int64_t block_number, char *buffer) {
u_int64_t offset = block_number * IO_BLOCK_SIZE;
if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) {
printf("LSEEK ERROR %llu %llu\n", block_number, offset);
perror("Error seeking to offset");
errno = EIO;
return -1;
}
// TODO: this is incorrect
ssize_t bytesRead = read(fd, buffer, IO_BLOCK_SIZE);
// printf("READ BLOCK: %llu\n", block_number);
// for (int i = 0; i < IO_BLOCK_SIZE; i++)printf("%x", buffer[i]&0xff);
// printf("\n");
if (bytesRead < IO_BLOCK_SIZE) {
perror("Error reading from device");
errno = EIO;
return -1;
}
@ -88,7 +80,6 @@ int RealRawDisk::write_block(u_int64_t block_number, char *buffer) {
if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) {
perror("Error seeking to offset");
errno = EIO;
return -1;
}
@ -96,7 +87,6 @@ int RealRawDisk::write_block(u_int64_t block_number, char *buffer) {
ssize_t bytesWritten = write(fd, buffer, IO_BLOCK_SIZE);
if (bytesWritten < IO_BLOCK_SIZE) {
perror("Error writing to device");
errno = EIO;
return -1;
}
@ -111,7 +101,7 @@ FakeRawDisk::FakeRawDisk(u_int64_t num_blocks) {
exit(1);
}
printf("====Initializing FAKE RawDisk====\n");
printf("FAKE Disk size (in bytes): %lu\n", diskSize);
printf("FAKE Disk size (in bytes): %llu\n", diskSize);
perror("!!! USING FAKE RawDisk - THIS IS FOR TESTING ONLY !!!");
}
@ -122,7 +112,6 @@ int FakeRawDisk::read_block(u_int64_t block_number, char *buffer) {
if (offset + IO_BLOCK_SIZE > diskSize) {
perror("Error reading past fake disk size");
errno = EIO;
return -1;
}
@ -136,7 +125,6 @@ int FakeRawDisk::write_block(u_int64_t block_number, char *buffer) {
if (offset + IO_BLOCK_SIZE > diskSize) {
perror("Error writing past fake disk size");
errno = EIO;
return -1;
}

View File

@ -1,69 +1,62 @@
# set(TARGET_LAYER0 test_layer0)
# set(TARGET_LAYER1_API test_layer1_API)
# set(TARGET_LAYER2_API test_layer2_API)
# set(TARGET_DIR_API test_dir_API)
# set(DIR_PLACE /dev/vdb)
# # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address")
set(TARGET_LAYER0 test_layer0)
set(TARGET_LAYER1_API test_layer1_API)
set(TARGET_LAYER2_API test_layer2_API)
set(TARGET_DIR_API test_dir_API)
set(DIR_PLACE /dev/vdb)
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address")
# # add test sources here ...
# add_executable(${TARGET_LAYER0}
# # add need lib and source code here
# layer0.cpp
# add test sources here ...
add_executable(${TARGET_LAYER0}
# add need lib and source code here
layer0.cpp
# ../lib/rawdisk.cpp
../lib/rawdisk.cpp
# )
# add_executable(${TARGET_LAYER1_API}
# # add need lib and source code here
# layer1_API.cpp
# ../lib/rawdisk.cpp
# ../lib/fs/datablock_manager.cpp
# ../lib/fs/fs_data_types.cpp
# ../lib/fs/fs_file_io.cpp
# ../lib/fs/fs.cpp
# ../lib/fs/inode_manager.cpp
# )
# add_executable(${TARGET_LAYER2_API}
# ../lib/direntry.cpp
# ../lib/rawdisk.cpp
# ../lib/fs/datablock_manager.cpp
# ../lib/fs/fs_data_types.cpp
# ../lib/fs/fs_file_io.cpp
# ../lib/fs/fs.cpp
# ../lib/fs/inode_manager.cpp
# ../lib/files.cpp
# layer2_API_dir.cpp
# )
# add_executable(${TARGET_DIR_API}
# ../lib/direntry.cpp
# ../lib/rawdisk.cpp
# ../lib/fs/datablock_manager.cpp
# ../lib/fs/fs_data_types.cpp
# ../lib/fs/fs_file_io.cpp
# ../lib/fs/fs.cpp
# ../lib/fs/inode_manager.cpp
# dir_API.cpp
# )
)
add_executable(${TARGET_LAYER1_API}
# add need lib and source code here
layer1_API.cpp
# # Link Google Test to your test executables
# target_link_libraries(${TARGET_LAYER0} gtest gtest_main)
# target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main)
# target_link_libraries(${TARGET_DIR_API} gtest gtest_main)
../lib/rawdisk.cpp
../lib/fs/datablock_manager.cpp
../lib/fs/fs_data_types.cpp
../lib/fs/fs_resize.cpp
../lib/fs/fs_read_write.cpp
../lib/fs/fs.cpp
../lib/fs/inode_manager.cpp
)
add_executable(${TARGET_LAYER2_API}
../lib/direntry.cpp
../lib/rawdisk.cpp
../lib/fs/datablock_manager.cpp
../lib/fs/fs_data_types.cpp
../lib/fs/fs_resize.cpp
../lib/fs/fs_read_write.cpp
../lib/fs/fs.cpp
../lib/fs/inode_manager.cpp
../lib/files.cpp
layer2_API_dir.cpp
)
add_executable(${TARGET_DIR_API}
../lib/direntry.cpp
../lib/rawdisk.cpp
../lib/fs/datablock_manager.cpp
../lib/fs/fs_data_types.cpp
../lib/fs/fs_resize.cpp
../lib/fs/fs_read_write.cpp
../lib/fs/fs.cpp
../lib/fs/inode_manager.cpp
dir_API.cpp
)
# # add test to activate ctest -VV
# add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE})
# add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE})
# add_test(NAME ${TARGET_LAYER2_API} COMMAND sudo ./${TARGET_LAYER2_API} ${DIR_PLACE})
# add_test(NAME ${TARGET_DIR_API} COMMAND sudo ./${TARGET_DIR_API} ${DIR_PLACE})
# Link Google Test to your test executables
target_link_libraries(${TARGET_LAYER0} gtest gtest_main)
target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main)
target_link_libraries(${TARGET_LAYER2_API} gtest gtest_main)
target_link_libraries(${TARGET_DIR_API} gtest gtest_main)
# # Add the -Wall flag
# target_compile_options(${TARGET_LAYER2_API} PRIVATE -Wall)
# # Use pkg-config to get flags for fuse3
# find_package(PkgConfig REQUIRED)
# pkg_search_module(FUSE3 REQUIRED fuse3)
# # Add the flags from pkg-config for fuse3
# target_include_directories(${TARGET_LAYER2_API} PRIVATE ${FUSE3_INCLUDE_DIRS})
# target_link_libraries(${TARGET_LAYER2_API} PRIVATE ${FUSE3_LIBRARIES} gtest gtest_main)
# add test to activate ctest -VV
add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE})
add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE})
add_test(NAME ${TARGET_LAYER2_API} COMMAND sudo ./${TARGET_LAYER2_API} ${DIR_PLACE})
add_test(NAME ${TARGET_DIR_API} COMMAND sudo ./${TARGET_DIR_API} ${DIR_PLACE})

View File

@ -12,7 +12,7 @@
#include <iostream>
#include "fs.hpp"
#include "direntry.h"
/*
typedef struct file_test{
const char* name;
file_test* next;//use linked-list to know the file at the same level directory
@ -217,7 +217,7 @@ TEST(DirTest, Add_FindFile_test) {
file_permissions = 0;
inode_dir.metadata.permissions = file_permissions | S_IFDIR;
// add with subdirectory
/*add with subdirectory*/
//Treenode dir(you cannot find here), you only can get Filenode dir based on fischl_find_entry Function
//So use Filenode->subdirectory will point to the treenode dir, then can add files
target_filepath = std::string("/") + mock_root->subdir->name + "/";
@ -240,7 +240,7 @@ TEST(DirTest, Add_FindFile_test) {
get_file = fischl_find_entry(get_dir->subdirectory,target_filepath.c_str());
EXPECT_TRUE(get_file != NULL);
EXPECT_STREQ(get_file->name, mock_root->subdir->inFile->name);
/**********************************************************/
//add one more file under fist subdir
fischl_add_entry(get_dir->subdirectory, 5, mock_root->subdir->inFile->next->name, &inode_file);
//add one more directory under fist subdir
@ -326,11 +326,10 @@ TEST(DirTest, Add_FindFile_test) {
// temp = temp->next; // Move to next subdir
// }
// }*/
// }
int main(int argc, char **argv) {
/*srand(time(NULL)); // Seed the random number generator
srand(time(NULL)); // Seed the random number generator
d = (argc < 2) ? "/dev/vdc" : argv[1];
setupTestDirectory(&mock_root);
@ -347,6 +346,5 @@ int main(int argc, char **argv) {
freeDirHierarchy(mock_root);//mock_root
printf("Free Total: Dir %d, File %d\n",total_free_dir, total_free_file);
freeTree(root);
return result;*/
return 0;
return result;
}

View File

@ -65,16 +65,13 @@ int main(int argc, char *argv[]) {
1); // the first 8 bytes of 4k I/O block will store
// the next address(after 2048*4k I/O block)
// test the end of the datablock
H->read_block(fs->disk->diskSize / IO_BLOCK_SIZE -
DATABLOCKS_PER_BITMAP_BLOCK - 1,
buffer);
H->read_block(fs->disk->diskSize/IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1, buffer);
t = 0;
for (int j = 0; j < 8; j++)
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
assert(t ==
fs->disk->diskSize / IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1);
assert(t == fs->disk->diskSize/IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1);
/***************************test inode
* de/allocation**********************************/
@ -112,35 +109,34 @@ int main(int argc, char *argv[]) {
// after free the datablock, the program will find the first smallest address
// of datablock to give to the inode should test random resize each node, but
// should use datablock_free data structure to record
// u_int64_t rec_datablock_free[10][3] = {0}; // array version
// u_int64_t temp_block_num = 0;
// for (int i = 0; i < 10; i++) {
// // printf("%dth data block starting addres: ", i);
// for (int j = 0; j < 6; j++) {
// fs->allocate_datablock(&inode_list[i], &temp_block_num);
// // printf("%d," ,inode_inside[i].datablock_allocate(*H));
// }
// // printf("\n");
// }
// for (int i = 0; i < 10; i++) {
// // printf("%dth data block free addres: ", i);
// for (int j = 2; j >= 0; j--) {
// fs->deallocate_datablock(&inode_list[i],
// &(rec_datablock_free[i][j]));
// // printf("", rec_datablock_free[i][j]);
// }
// // printf("\n");
// }
u_int64_t rec_datablock_free[10][3] = {0}; // array version
u_int64_t temp_block_num = 0;
for (int i = 0; i < 10; i++) {
printf("%dth data block starting addres: ", i);
for (int j = 0; j < 6; j++) {
fs->allocate_datablock(&inode_list[i], &temp_block_num);
printf("%llu," ,temp_block_num);
}
printf("\n");
}
for (int i = 0; i < 10; i++) {
printf("%dth data block free addres: ", i);
for (int j = 2; j >= 0; j--) {
fs->deallocate_datablock(&inode_list[i], &(rec_datablock_free[i][j]));
printf("%llu,", rec_datablock_free[i][j]);
}
printf("\n");
}
// for (int i = 0; i < 10; i++) {
// // printf("%dth data block allocate again addres: ", i);
// for (int j = 0; j < 3; j++) {
// fs->allocate_datablock(&inode_list[i], &temp_block_num);
// assert(temp_block_num == rec_datablock_free[i][j]);
// // printf("%d," ,inode_inside[i].datablock_allocate(*H));
// }
// // printf("\n");
// }
for (int i = 0; i < 10; i++) {
printf("%dth data block allocate again addres: ", i);
for (int j = 0; j < 3; j++) {
fs->allocate_datablock(&inode_list[i], &temp_block_num);
//assert(temp_block_num == rec_datablock_free[i][j]);
printf("%llu," ,temp_block_num);
}
printf("\n");
}
// printf("}\n");
delete H; // Delete the RawDisk object

View File

@ -1,5 +1,3 @@
#define FUSE_USE_VERSION 31
#include <stdio.h>
#include <string>
#include <assert.h>
@ -39,10 +37,6 @@ int total_file_num = 0;
int total_free_dir = 0;
int total_free_file = 0;
FileNode* fischl_load_entry(TreeNode *root, const char *path){
return fischl_find_entry(fs, root, path);
}
TEST(FileOperationTest, MkdirnodTest) {
fsop->initialize_rootinode();
@ -99,19 +93,19 @@ TEST(FileOperationTest, RamDiskTest) {
FileNode* get_dir;
u_int64_t get_disk_inum;
get_dir = fischl_load_entry(fsop->root_node, "/test");//this is file
get_dir = fischl_find_entry(fsop->root_node, "/test");//this is file
EXPECT_TRUE(get_dir != NULL);//detect this should find success
EXPECT_STREQ(get_dir->name, "test");
get_disk_inum = fsop->disk_namei("/test");
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
get_dir = fischl_load_entry(fsop->root_node, "/foo/bar/baz");//this is file
get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/baz");//this is file
EXPECT_TRUE(get_dir != NULL);//detect this should find success
EXPECT_STREQ(get_dir->name, "baz");
get_disk_inum = fsop->disk_namei("/foo/bar/baz");
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
get_dir = fischl_load_entry(fsop->root_node, "/foo/bar/..");
get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/..");
EXPECT_TRUE(get_dir != NULL);//detect this should find success
EXPECT_STREQ(get_dir->name, "foo");
ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory
@ -119,7 +113,7 @@ TEST(FileOperationTest, RamDiskTest) {
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
fsop->printDirectory(get_disk_inum);
get_dir = fischl_load_entry(fsop->root_node, "/foo/bar/.");
get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/.");
EXPECT_TRUE(get_dir != NULL);//detect this should find success
EXPECT_STREQ(get_dir->name, "bar");
ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory