Merge pull request #14 from SuperconductZB/guangzheliu/layer3dev
Implement Layer3
This commit is contained in:
commit
fb961a9cd5
@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14)
|
|||||||
include_directories(
|
include_directories(
|
||||||
# fischl include files
|
# fischl include files
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include
|
# ${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(fischl
|
add_executable(fischl
|
||||||
@ -16,8 +16,7 @@ add_executable(fischl
|
|||||||
lib/rawdisk.cpp
|
lib/rawdisk.cpp
|
||||||
lib/fs/datablock_manager.cpp
|
lib/fs/datablock_manager.cpp
|
||||||
lib/fs/fs_data_types.cpp
|
lib/fs/fs_data_types.cpp
|
||||||
lib/fs/fs_resize.cpp
|
lib/fs/fs_file_io.cpp
|
||||||
lib/fs/fs_read_write.cpp
|
|
||||||
lib/fs/fs.cpp
|
lib/fs/fs.cpp
|
||||||
lib/fs/inode_manager.cpp
|
lib/fs/inode_manager.cpp
|
||||||
lib/files.cpp
|
lib/files.cpp
|
||||||
@ -27,4 +26,15 @@ add_executable(fischl
|
|||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
add_subdirectory(googletest)
|
add_subdirectory(googletest)
|
||||||
|
|
||||||
|
# Add the -Wall flag
|
||||||
|
target_compile_options(fischl 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(fischl PRIVATE ${FUSE3_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(fischl PRIVATE ${FUSE3_LIBRARIES})
|
23
README.md
23
README.md
@ -19,6 +19,29 @@ cmake ..
|
|||||||
make # cmake --build . is same
|
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
|
## run test
|
||||||
### add your own test file on test/CMakeList.txt
|
### add your own test file on test/CMakeList.txt
|
||||||
```
|
```
|
||||||
|
@ -19,18 +19,48 @@ typedef struct treeNode {
|
|||||||
FileNode *self_info; //self fileNode infromation
|
FileNode *self_info; //self fileNode infromation
|
||||||
} TreeNode;
|
} 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*/
|
/*for root*/
|
||||||
TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode_Data *new_inode);
|
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 */
|
/*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*/
|
/*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_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode);
|
||||||
int fischl_rm_entry(TreeNode *parent, const char *fileName);
|
int fischl_rm_entry(TreeNode *parent, const char *fileName);
|
||||||
/*if want to use dir mode use the subdirectory treeNode pointer */
|
/*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. 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;
|
//e.g. go to the current Dirnode parent directory, use TreeNode *get_Dir_parent = Dirnode->subdirectory->parent;
|
||||||
FileNode *fischl_find_entry(TreeNode *root, const char *path);
|
FileNode *fischl_find_entry(Fs *fs, TreeNode *root, const char *path);
|
||||||
|
|
||||||
void freeTree(TreeNode *node);
|
void freeTree(TreeNode *node);
|
||||||
/*for debug use*/
|
/*for debug use*/
|
||||||
TreeNode *createDirectory(const char *dirName, TreeNode *parent, int hashSize);
|
TreeNode *createDirectory(const char *dirName, TreeNode *parent, int hashSize);
|
||||||
TreeNode *find_parentPath(TreeNode *root, const char *path);
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <fs.hpp>
|
#include <fs.hpp>
|
||||||
#include "fuse_common.h"
|
#include <fuse.h>
|
||||||
#include "direntry.h"
|
#include "direntry.h"
|
||||||
|
|
||||||
class FilesOperation {
|
class FilesOperation {
|
||||||
@ -8,25 +8,44 @@ class FilesOperation {
|
|||||||
Fs *fs;
|
Fs *fs;
|
||||||
void create_dot_dotdot(INode_Data*, u_int64_t);
|
void create_dot_dotdot(INode_Data*, u_int64_t);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TreeNode *root_node;
|
TreeNode *root_node;
|
||||||
FilesOperation(RawDisk&, Fs*);
|
FilesOperation(RawDisk&, Fs*);
|
||||||
//int read_datablock(const INode_Data& inode, u_int64_t index, char* buffer);
|
//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);
|
//int write_datablock(INode_Data& inode, u_int64_t index, char* buffer);
|
||||||
void initialize_rootinode();
|
void initialize_rootinode();
|
||||||
|
void initialize(bool load);
|
||||||
void printbuffer(const char*,int);
|
void printbuffer(const char*,int);
|
||||||
void printDirectory(u_int64_t);
|
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);
|
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);
|
void unlink_inode(u_int64_t inode_number);
|
||||||
u_int64_t disk_namei(const char* path);
|
u_int64_t disk_namei(const char* path);
|
||||||
u_int64_t namei(const char* path);
|
u_int64_t namei(const char* path);
|
||||||
int fischl_mkdir(const char*, mode_t);
|
int fischl_mkdir(const char*, mode_t);
|
||||||
int fischl_mknod(const char*, mode_t, dev_t);//for special file
|
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_create(const char *, mode_t, struct fuse_file_info *);//for regular file
|
||||||
//int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags);
|
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_unlink (const char *);
|
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_open (const char *, struct fuse_file_info *);//open file
|
||||||
int fischl_release (const char *, struct fuse_file_info *);//close 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_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_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);
|
||||||
|
};
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
class fischl{
|
|
||||||
|
|
||||||
// declare
|
|
||||||
public:
|
|
||||||
int init();
|
|
||||||
|
|
||||||
};
|
int fischl(int argc, char *argv[]);
|
||||||
|
@ -15,20 +15,12 @@ public:
|
|||||||
Fs(RawDisk *disk);
|
Fs(RawDisk *disk);
|
||||||
~Fs();
|
~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 read(INode_Data *inode_data, char buf[], size_t count, size_t offset);
|
||||||
ssize_t write(INode_Data *inode_data, char buf[], size_t count,
|
ssize_t write(INode_Data *inode_data, const char buf[], size_t count,
|
||||||
size_t offset);
|
size_t offset);
|
||||||
|
int truncate(INode_Data *inode_data, size_t length);
|
||||||
int sweep_inode_datablocks(INode_Data *inode_data,
|
ssize_t lseek_next_data(INode_Data *inode_data, size_t offset);
|
||||||
u_int64_t start_block_index, bool allocate,
|
ssize_t lseek_next_hole(INode_Data *inode_data, size_t offset);
|
||||||
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();
|
int format();
|
||||||
|
|
||||||
@ -44,8 +36,13 @@ public:
|
|||||||
int save_free_list_head(u_int64_t new_free_list_head);
|
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 save_inode_list_head(u_int64_t new_inode_list_head);
|
||||||
|
|
||||||
int allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num);
|
int sweep_inode_datablocks(INode_Data *inode_data,
|
||||||
int deallocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -25,12 +25,14 @@ public:
|
|||||||
u_int64_t inode_num;
|
u_int64_t inode_num;
|
||||||
|
|
||||||
#define NUMBER_OF_METADATA_BYTES \
|
#define NUMBER_OF_METADATA_BYTES \
|
||||||
(4 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t)))
|
(6 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t)))
|
||||||
struct INode_MetaData {
|
struct INode_MetaData {
|
||||||
u_int64_t uid;
|
u_int64_t uid;
|
||||||
u_int64_t gid;
|
u_int64_t gid;
|
||||||
u_int64_t permissions;
|
u_int64_t permissions;
|
||||||
u_int64_t size; // not yet implemented
|
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 reference_count;
|
||||||
u_int32_t flags;
|
u_int32_t flags;
|
||||||
} metadata;
|
} metadata;
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define IO_BLOCK_SIZE 4096
|
#define IO_BLOCK_SIZE 4096
|
||||||
|
#define INDIRECT_BLOCKS 512
|
||||||
|
|
||||||
#define NUM_INODE_BLOCKS 1023
|
#define NUM_INODE_BLOCKS 1023
|
||||||
#define NUM_BLOCKS 2048
|
|
||||||
|
|
||||||
#define INODE_SIZE 512
|
#define INODE_SIZE 512
|
||||||
|
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
#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_ */
|
|
@ -156,6 +156,26 @@ TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode_Da
|
|||||||
return newDir;
|
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){
|
int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode){
|
||||||
char *Name = strdup(fileName);
|
char *Name = strdup(fileName);
|
||||||
TreeNode *newDir = NULL;
|
TreeNode *newDir = NULL;
|
||||||
@ -191,13 +211,15 @@ int fischl_rm_entry(TreeNode *parent, const char *fileName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FileNode *fischl_find_entry(TreeNode *root, const char *path){
|
FileNode *fischl_find_entry(Fs *fs, TreeNode *root, const char *path){
|
||||||
//support . and .. function
|
//support . and .. function
|
||||||
char *pathCopy = strdup(path);
|
char *pathCopy = strdup(path);
|
||||||
char *segment = strtok(pathCopy, "/");
|
char *segment = strtok(pathCopy, "/");
|
||||||
TreeNode *current = root;
|
TreeNode *current = root;
|
||||||
FileNode *file = NULL;
|
FileNode *file = NULL;
|
||||||
|
|
||||||
|
printf("FINDING %s %s %llu\n", path, segment, current->self_info->inode_number);
|
||||||
|
|
||||||
while (segment != NULL && current != NULL) {
|
while (segment != NULL && current != NULL) {
|
||||||
if (strcmp(segment, "..") == 0) {
|
if (strcmp(segment, "..") == 0) {
|
||||||
// Move up to the parent directory
|
// Move up to the parent directory
|
||||||
@ -214,8 +236,29 @@ FileNode *fischl_find_entry(TreeNode *root, const char *path){
|
|||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
file = lookupHash(current->contents, segment);
|
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) {
|
if (file != NULL && file->subdirectory == NULL) {
|
||||||
free(pathCopy);
|
free(pathCopy);
|
||||||
|
printf("FOUND !! %llu\n", file->inode_number);
|
||||||
return file; //File found
|
return file; //File found
|
||||||
//return current; return filenode
|
//return current; return filenode
|
||||||
}
|
}
|
||||||
|
1210
lib/files.cpp
1210
lib/files.cpp
File diff suppressed because it is too large
Load Diff
319
lib/fischl.cpp
319
lib/fischl.cpp
@ -1,8 +1,313 @@
|
|||||||
#include "fischl.h"
|
#define FUSE_USE_VERSION 31
|
||||||
|
|
||||||
#include <cstdio>
|
#include <fuse.h>
|
||||||
|
#include <stdio.h>
|
||||||
int fischl::init(){
|
#include <string>
|
||||||
printf("Hello Fischl!");
|
#include <errno.h>
|
||||||
return 3;
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "fs.hpp"
|
||||||
|
#include "files.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command line options
|
||||||
|
*
|
||||||
|
* We can't set default values for the char* fields here because
|
||||||
|
* fuse_opt_parse would attempt to free() them when the user specifies
|
||||||
|
* different values on the command line.
|
||||||
|
*/
|
||||||
|
static struct options {
|
||||||
|
RawDisk *H; // Use FakeRawDisk here if memory sanitizer complains
|
||||||
|
Fs *fs;
|
||||||
|
FilesOperation *fsop;
|
||||||
|
int show_help;
|
||||||
|
bool load;
|
||||||
|
} options;
|
||||||
|
|
||||||
|
#define OPTION(t, p) \
|
||||||
|
{ t, offsetof(struct options, p), 1 }
|
||||||
|
static const struct fuse_opt option_spec[] = {
|
||||||
|
OPTION("-h", show_help),
|
||||||
|
OPTION("--help", show_help),
|
||||||
|
FUSE_OPT_END
|
||||||
|
};
|
||||||
|
|
||||||
|
void* fischl_init(struct fuse_conn_info *conn, struct fuse_config *cfg) {
|
||||||
|
cfg->use_ino = 1;
|
||||||
|
options.fsop->initialize(options.load);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fischl_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
|
||||||
|
return options.fsop->fischl_create(path, mode, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_access(const char* path, int mask) {
|
||||||
|
return options.fsop->fischl_access(path, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_readlink(const char* path, char* buf, size_t size) {
|
||||||
|
return options.fsop->fischl_readlink(path, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_opendir(const char* path, struct fuse_file_info* fi) {
|
||||||
|
return options.fsop->fischl_opendir(path, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_mknod(const char* path, mode_t mode, dev_t rdev) {
|
||||||
|
return options.fsop->fischl_mknod(path, mode, rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_mkdir(const char *path, mode_t mode) {
|
||||||
|
return options.fsop->fischl_mkdir(path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_unlink(const char* path) {
|
||||||
|
return options.fsop->fischl_unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_rmdir(const char* path) {
|
||||||
|
return options.fsop->fischl_rmdir(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_symlink(const char* from, const char* to) {
|
||||||
|
return options.fsop->fischl_symlink(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_link(const char* from, const char* to) {
|
||||||
|
return options.fsop->fischl_link(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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_truncate(const char *path, off_t offset, struct fuse_file_info *fi) {
|
||||||
|
return options.fsop->fischl_truncate(path, offset, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_open(const char *path, struct fuse_file_info *fi) {
|
||||||
|
return options.fsop->fischl_open(path, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_read(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi) {
|
||||||
|
return options.fsop->fischl_read(path, buf, size, offset, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_statfs(const char* path, struct statvfs* stbuf) {
|
||||||
|
return options.fsop->fischl_statfs(path, stbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_release(const char* path, struct fuse_file_info *fi) {
|
||||||
|
return options.fsop->fischl_release(path, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fischl_releasedir(const char* path, struct fuse_file_info *fi) {
|
||||||
|
return options.fsop->fischl_releasedir(path, fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct fuse_operations fischl_oper = {
|
||||||
|
|
||||||
|
|
||||||
|
.getattr = fischl_getattr,
|
||||||
|
.readlink = fischl_readlink,
|
||||||
|
.mknod = fischl_mknod,
|
||||||
|
.mkdir = fischl_mkdir,
|
||||||
|
.unlink = fischl_unlink,
|
||||||
|
.rmdir = fischl_rmdir,
|
||||||
|
.symlink = fischl_symlink,
|
||||||
|
.rename = fischl_rename,
|
||||||
|
.link = fischl_link,
|
||||||
|
.chmod = fischl_chmod,
|
||||||
|
.chown = fischl_chown,
|
||||||
|
.truncate = fischl_truncate,
|
||||||
|
.open = fischl_open,
|
||||||
|
.read = fischl_read,
|
||||||
|
.write = fischl_write,
|
||||||
|
.statfs = fischl_statfs,
|
||||||
|
.release = fischl_release,
|
||||||
|
/*
|
||||||
|
#ifdef HAVE_SETXATTR
|
||||||
|
.setxattr = fischl_setxattr,
|
||||||
|
.getxattr = fischl_getxattr,
|
||||||
|
.listxattr = fischl_listxattr,
|
||||||
|
.removexattr = fischl_removexattr,
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
.opendir = fischl_opendir,
|
||||||
|
.readdir = fischl_readdir,
|
||||||
|
.releasedir = fischl_releasedir,
|
||||||
|
.init = fischl_init,
|
||||||
|
.destroy = fischl_destroy,
|
||||||
|
.access = fischl_access,
|
||||||
|
.create = fischl_create,
|
||||||
|
.utimens = fischl_utimens,
|
||||||
|
//.bmap = fischl_bmap,
|
||||||
|
//.ioctl = fischl_ioctl,
|
||||||
|
//.poll = fischl_poll,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void show_help(const char *progname)
|
||||||
|
{
|
||||||
|
printf("usage: %s [options] <mountpoint>\n\n", progname);
|
||||||
|
printf("File-system specific options:\n"
|
||||||
|
" --name=<s> Name of the \"fischl\" file\n"
|
||||||
|
" (default: \"fischl\")\n"
|
||||||
|
" --contents=<s> Contents \"fischl\" file\n"
|
||||||
|
" (default \"fischl, World!\\n\")\n"
|
||||||
|
"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
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.fs = new Fs(options.H);
|
||||||
|
if(!options.load){
|
||||||
|
printf("FORMAT %d\n", 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 */
|
||||||
|
if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* When --help is specified, first print our own file-system
|
||||||
|
specific help text, then signal fuse_main to show
|
||||||
|
additional help (by adding `--help` to the options again)
|
||||||
|
without usage: line (by setting argv[0] to the empty
|
||||||
|
string) */
|
||||||
|
if (options.show_help) {
|
||||||
|
show_help(argv[0]);
|
||||||
|
assert(fuse_opt_add_arg(&args, "--help") == 0);
|
||||||
|
args.argv[0][0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fuse_main(args.argc, args.argv, &fischl_oper, NULL);
|
||||||
|
fuse_opt_free_args(&args);
|
||||||
|
return ret;
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
|
|
||||||
DataBlock_Manager::DataBlock_Manager(Fs *fs, u_int64_t block_segment_start,
|
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),
|
: fs(fs), block_segment_start(block_segment_start),
|
||||||
block_segment_end(block_segment_end) {}
|
block_segment_end(block_segment_end) {}
|
||||||
|
|
||||||
@ -58,6 +58,10 @@ int DataBlock_Manager_Bitmap::new_datablock(u_int64_t *block_num) {
|
|||||||
if ((err = fs->disk->read_block(bitmap_block_num, bitmap.buf)) < 0)
|
if ((err = fs->disk->read_block(bitmap_block_num, bitmap.buf)) < 0)
|
||||||
return err;
|
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();
|
u_int64_t relative_block_num = bitmap.claim_relative_block();
|
||||||
|
|
||||||
if (relative_block_num == 0)
|
if (relative_block_num == 0)
|
||||||
@ -122,6 +126,7 @@ int DataBlock_Manager_Bitmap::format() {
|
|||||||
char buf[IO_BLOCK_SIZE] = {0};
|
char buf[IO_BLOCK_SIZE] = {0};
|
||||||
int err;
|
int err;
|
||||||
u_int64_t i = block_segment_start;
|
u_int64_t i = block_segment_start;
|
||||||
|
write_u64(i, buf);
|
||||||
for (; i <= block_segment_end - (2 * bitmap_region_size);
|
for (; i <= block_segment_end - (2 * bitmap_region_size);
|
||||||
i += bitmap_region_size) {
|
i += bitmap_region_size) {
|
||||||
write_u64(i + bitmap_region_size, buf);
|
write_u64(i + bitmap_region_size, buf);
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
Fs::Fs(RawDisk *disk) : disk(disk) {
|
Fs::Fs(RawDisk *disk) : disk(disk) {
|
||||||
|
assert((disk->diskSize / IO_BLOCK_SIZE) >
|
||||||
|
2 + NUM_INODE_BLOCKS + DATABLOCKS_PER_BITMAP_BLOCK);
|
||||||
superblock = SuperBlock_Data();
|
superblock = SuperBlock_Data();
|
||||||
inode_manager = new INode_Manager_Freelist(this, 1, 1 + NUM_INODE_BLOCKS);
|
inode_manager = new INode_Manager_Freelist(this, 1, 1 + NUM_INODE_BLOCKS);
|
||||||
datablock_manager =
|
datablock_manager = new DataBlock_Manager_Bitmap(
|
||||||
new DataBlock_Manager_Bitmap(this, 1 + NUM_INODE_BLOCKS, disk->diskSize/IO_BLOCK_SIZE);
|
this, 1 + NUM_INODE_BLOCKS, disk->diskSize / IO_BLOCK_SIZE);
|
||||||
};
|
};
|
||||||
|
|
||||||
Fs::~Fs() {
|
Fs::~Fs() {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
template <typename T> T write_int(T num, char buf[]) {
|
template <typename T> T write_int(T num, char buf[]) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@ -50,11 +51,15 @@ void SuperBlock_Data::deserialize(char buf[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
INode_Data::INode_Data(u_int64_t inode_num) : inode_num(inode_num) {
|
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.uid = -1;
|
||||||
metadata.gid = -1;
|
metadata.gid = -1;
|
||||||
metadata.permissions = -1;
|
metadata.permissions = -1;
|
||||||
metadata.size = 0;
|
metadata.size = 0;
|
||||||
metadata.reference_count = 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;
|
||||||
|
|
||||||
single_indirect_block = double_indirect_block = triple_indirect_block = 0;
|
single_indirect_block = double_indirect_block = triple_indirect_block = 0;
|
||||||
|
|
||||||
@ -68,6 +73,8 @@ size_t INode_Data::serialize_metadata(char buf[]) {
|
|||||||
i += write_u64(metadata.gid, &buf[i]);
|
i += write_u64(metadata.gid, &buf[i]);
|
||||||
i += write_u64(metadata.permissions, &buf[i]);
|
i += write_u64(metadata.permissions, &buf[i]);
|
||||||
i += write_u64(metadata.size, &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.reference_count, &buf[i]);
|
||||||
i += write_u32(metadata.flags, &buf[i]);
|
i += write_u32(metadata.flags, &buf[i]);
|
||||||
return i;
|
return i;
|
||||||
@ -79,6 +86,8 @@ size_t INode_Data::deserialize_metadata(char buf[]) {
|
|||||||
i += read_u64(&metadata.gid, &buf[i]);
|
i += read_u64(&metadata.gid, &buf[i]);
|
||||||
i += read_u64(&metadata.permissions, &buf[i]);
|
i += read_u64(&metadata.permissions, &buf[i]);
|
||||||
i += read_u64(&metadata.size, &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.reference_count, &buf[i]);
|
||||||
i += read_u32(&metadata.flags, &buf[i]);
|
i += read_u32(&metadata.flags, &buf[i]);
|
||||||
return i;
|
return i;
|
||||||
|
391
lib/fs/fs_file_io.cpp
Normal file
391
lib/fs/fs_file_io.cpp
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
#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;
|
||||||
|
|
||||||
|
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, size_t length) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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;
|
||||||
|
}
|
@ -1,212 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char *argv[]) {
|
||||||
// printf("hello word!");
|
// printf("hello word!");
|
||||||
// fischl *F = new fischl;
|
// fischl *F = new fischl;
|
||||||
// F->init();
|
// F->init();
|
||||||
@ -34,6 +34,7 @@ int main() {
|
|||||||
|
|
||||||
// disk->print_block(1597);
|
// disk->print_block(1597);
|
||||||
|
|
||||||
|
/*
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
RawDisk *disk = new FakeRawDisk(2048);
|
RawDisk *disk = new FakeRawDisk(2048);
|
||||||
@ -80,7 +81,11 @@ int main() {
|
|||||||
printf("\n\nREAD: %d\n", err);
|
printf("\n\nREAD: %d\n", err);
|
||||||
for (int i = 0; i < N; ++i)
|
for (int i = 0; i < N; ++i)
|
||||||
printf("%d ", buf2[i]);
|
printf("%d ", buf2[i]);
|
||||||
printf("\n");
|
printf("\n");*/
|
||||||
|
|
||||||
|
fischl(argc, argv);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -10,12 +10,12 @@ void RawDisk::print_block(u_int64_t block_number) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nBlock %llu:\n", block_number);
|
printf("\nBlock %lu:\n", block_number);
|
||||||
for (int i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) {
|
for (int i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) {
|
||||||
num = 0;
|
num = 0;
|
||||||
for (int j = 0; j < 8; j++)
|
for (int j = 0; j < 8; j++)
|
||||||
num |= ((u_int64_t)(unsigned char)buf[i + j]) << (8 * j);
|
num |= ((u_int64_t)(unsigned char)buf[i + j]) << (8 * j);
|
||||||
printf("%llu ", num);
|
printf("%lu ", num);
|
||||||
if ((i / sizeof(u_int64_t)) % nums_per_line == nums_per_line - 1)
|
if ((i / sizeof(u_int64_t)) % nums_per_line == nums_per_line - 1)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
@ -43,12 +43,14 @@ RealRawDisk::RealRawDisk(const char *directory)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//diskSize = 27648 * IO_BLOCK_SIZE;
|
||||||
|
|
||||||
// Calculate the size in bytes
|
// Calculate the size in bytes
|
||||||
numSectors = diskSize / 512; // Assuming a sector size of 512 bytes
|
numSectors = diskSize / 512; // Assuming a sector size of 512 bytes
|
||||||
|
|
||||||
printf("====Initializing RawDisk====\n");
|
printf("====Initializing RawDisk====\n");
|
||||||
printf("Number of sectors: %llu\n", numSectors);
|
printf("Number of sectors: %lu\n", numSectors);
|
||||||
printf("Disk size (in bytes): %llu\n", diskSize);
|
printf("Disk size (in bytes): %lu\n", diskSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
RealRawDisk::~RealRawDisk() {
|
RealRawDisk::~RealRawDisk() {
|
||||||
@ -61,12 +63,16 @@ int RealRawDisk::read_block(u_int64_t block_number, char *buffer) {
|
|||||||
u_int64_t offset = block_number * IO_BLOCK_SIZE;
|
u_int64_t offset = block_number * IO_BLOCK_SIZE;
|
||||||
|
|
||||||
if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) {
|
if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) {
|
||||||
|
printf("LSEEK ERROR %llu %llu\n", block_number, offset);
|
||||||
perror("Error seeking to offset");
|
perror("Error seeking to offset");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is incorrect
|
// TODO: this is incorrect
|
||||||
ssize_t bytesRead = read(fd, buffer, IO_BLOCK_SIZE);
|
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) {
|
if (bytesRead < IO_BLOCK_SIZE) {
|
||||||
perror("Error reading from device");
|
perror("Error reading from device");
|
||||||
return -1;
|
return -1;
|
||||||
@ -101,7 +107,7 @@ FakeRawDisk::FakeRawDisk(u_int64_t num_blocks) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
printf("====Initializing FAKE RawDisk====\n");
|
printf("====Initializing FAKE RawDisk====\n");
|
||||||
printf("FAKE Disk size (in bytes): %llu\n", diskSize);
|
printf("FAKE Disk size (in bytes): %lu\n", diskSize);
|
||||||
perror("!!! USING FAKE RawDisk - THIS IS FOR TESTING ONLY !!!");
|
perror("!!! USING FAKE RawDisk - THIS IS FOR TESTING ONLY !!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,63 +1,69 @@
|
|||||||
set(TARGET_LAYER0 test_layer0)
|
# set(TARGET_LAYER0 test_layer0)
|
||||||
set(TARGET_LAYER1_API test_layer1_API)
|
# set(TARGET_LAYER1_API test_layer1_API)
|
||||||
set(TARGET_LAYER2_API test_layer2_API)
|
# set(TARGET_LAYER2_API test_layer2_API)
|
||||||
set(TARGET_DIR_API test_dir_API)
|
# set(TARGET_DIR_API test_dir_API)
|
||||||
set(DIR_PLACE /dev/vdb)
|
# set(DIR_PLACE /dev/vdb)
|
||||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address")
|
# # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address")
|
||||||
|
|
||||||
# add test sources here ...
|
# # add test sources here ...
|
||||||
add_executable(${TARGET_LAYER0}
|
# add_executable(${TARGET_LAYER0}
|
||||||
# add need lib and source code here
|
# # add need lib and source code here
|
||||||
layer0.cpp
|
# layer0.cpp
|
||||||
|
|
||||||
../lib/rawdisk.cpp
|
# ../lib/rawdisk.cpp
|
||||||
|
|
||||||
)
|
# )
|
||||||
add_executable(${TARGET_LAYER1_API}
|
# add_executable(${TARGET_LAYER1_API}
|
||||||
# add need lib and source code here
|
# # add need lib and source code here
|
||||||
layer1_API.cpp
|
# 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
|
||||||
|
# )
|
||||||
|
|
||||||
../lib/fischl.cpp
|
# # Link Google Test to your test executables
|
||||||
../lib/rawdisk.cpp
|
# target_link_libraries(${TARGET_LAYER0} gtest gtest_main)
|
||||||
../lib/fs/datablock_manager.cpp
|
# target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main)
|
||||||
../lib/fs/fs_data_types.cpp
|
# target_link_libraries(${TARGET_DIR_API} gtest gtest_main)
|
||||||
../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
|
|
||||||
)
|
|
||||||
|
|
||||||
# Link Google Test to your test executables
|
# # add test to activate ctest -VV
|
||||||
target_link_libraries(${TARGET_LAYER0} gtest gtest_main)
|
# add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE})
|
||||||
target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main)
|
# add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE})
|
||||||
target_link_libraries(${TARGET_LAYER2_API} gtest gtest_main)
|
# add_test(NAME ${TARGET_LAYER2_API} COMMAND sudo ./${TARGET_LAYER2_API} ${DIR_PLACE})
|
||||||
target_link_libraries(${TARGET_DIR_API} gtest gtest_main)
|
# add_test(NAME ${TARGET_DIR_API} COMMAND sudo ./${TARGET_DIR_API} ${DIR_PLACE})
|
||||||
|
|
||||||
# add test to activate ctest -VV
|
|
||||||
add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE})
|
# # Add the -Wall flag
|
||||||
add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE})
|
# target_compile_options(${TARGET_LAYER2_API} PRIVATE -Wall)
|
||||||
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})
|
# # 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)
|
@ -12,7 +12,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "direntry.h"
|
#include "direntry.h"
|
||||||
|
/*
|
||||||
typedef struct file_test{
|
typedef struct file_test{
|
||||||
const char* name;
|
const char* name;
|
||||||
file_test* next;//use linked-list to know the file at the same level directory
|
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;
|
file_permissions = 0;
|
||||||
inode_dir.metadata.permissions = file_permissions | S_IFDIR;
|
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
|
//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
|
//So use Filenode->subdirectory will point to the treenode dir, then can add files
|
||||||
target_filepath = std::string("/") + mock_root->subdir->name + "/";
|
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());
|
get_file = fischl_find_entry(get_dir->subdirectory,target_filepath.c_str());
|
||||||
EXPECT_TRUE(get_file != NULL);
|
EXPECT_TRUE(get_file != NULL);
|
||||||
EXPECT_STREQ(get_file->name, mock_root->subdir->inFile->name);
|
EXPECT_STREQ(get_file->name, mock_root->subdir->inFile->name);
|
||||||
/**********************************************************/
|
|
||||||
//add one more file under fist subdir
|
//add one more file under fist subdir
|
||||||
fischl_add_entry(get_dir->subdirectory, 5, mock_root->subdir->inFile->next->name, &inode_file);
|
fischl_add_entry(get_dir->subdirectory, 5, mock_root->subdir->inFile->next->name, &inode_file);
|
||||||
//add one more directory under fist subdir
|
//add one more directory under fist subdir
|
||||||
@ -326,10 +326,11 @@ TEST(DirTest, Add_FindFile_test) {
|
|||||||
|
|
||||||
// temp = temp->next; // Move to next subdir
|
// temp = temp->next; // Move to next subdir
|
||||||
// }
|
// }
|
||||||
// }
|
// }*/
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
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];
|
d = (argc < 2) ? "/dev/vdc" : argv[1];
|
||||||
|
|
||||||
setupTestDirectory(&mock_root);
|
setupTestDirectory(&mock_root);
|
||||||
@ -346,5 +347,6 @@ int main(int argc, char **argv) {
|
|||||||
freeDirHierarchy(mock_root);//mock_root
|
freeDirHierarchy(mock_root);//mock_root
|
||||||
printf("Free Total: Dir %d, File %d\n",total_free_dir, total_free_file);
|
printf("Free Total: Dir %d, File %d\n",total_free_dir, total_free_file);
|
||||||
freeTree(root);
|
freeTree(root);
|
||||||
return result;
|
return result;*/
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -65,13 +65,16 @@ int main(int argc, char *argv[]) {
|
|||||||
1); // the first 8 bytes of 4k I/O block will store
|
1); // the first 8 bytes of 4k I/O block will store
|
||||||
// the next address(after 2048*4k I/O block)
|
// the next address(after 2048*4k I/O block)
|
||||||
// test the end of the datablock
|
// 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;
|
t = 0;
|
||||||
for (int j = 0; j < 8; j++)
|
for (int j = 0; j < 8; j++)
|
||||||
t |= ((u_int64_t)(unsigned char)buffer[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
|
/***************************test inode
|
||||||
* de/allocation**********************************/
|
* de/allocation**********************************/
|
||||||
@ -109,34 +112,35 @@ int main(int argc, char *argv[]) {
|
|||||||
// after free the datablock, the program will find the first smallest address
|
// 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
|
// of datablock to give to the inode should test random resize each node, but
|
||||||
// should use datablock_free data structure to record
|
// should use datablock_free data structure to record
|
||||||
u_int64_t rec_datablock_free[10][3] = {0}; // array version
|
// u_int64_t rec_datablock_free[10][3] = {0}; // array version
|
||||||
u_int64_t temp_block_num = 0;
|
// u_int64_t temp_block_num = 0;
|
||||||
for (int i = 0; i < 10; i++) {
|
// for (int i = 0; i < 10; i++) {
|
||||||
printf("%dth data block starting addres: ", i);
|
// // printf("%dth data block starting addres: ", i);
|
||||||
for (int j = 0; j < 6; j++) {
|
// for (int j = 0; j < 6; j++) {
|
||||||
fs->allocate_datablock(&inode_list[i], &temp_block_num);
|
// fs->allocate_datablock(&inode_list[i], &temp_block_num);
|
||||||
printf("%llu," ,temp_block_num);
|
// // printf("%d," ,inode_inside[i].datablock_allocate(*H));
|
||||||
}
|
// }
|
||||||
printf("\n");
|
// // printf("\n");
|
||||||
}
|
// }
|
||||||
for (int i = 0; i < 10; i++) {
|
// for (int i = 0; i < 10; i++) {
|
||||||
printf("%dth data block free addres: ", i);
|
// // printf("%dth data block free addres: ", i);
|
||||||
for (int j = 2; j >= 0; j--) {
|
// for (int j = 2; j >= 0; j--) {
|
||||||
fs->deallocate_datablock(&inode_list[i], &(rec_datablock_free[i][j]));
|
// fs->deallocate_datablock(&inode_list[i],
|
||||||
printf("%llu,", rec_datablock_free[i][j]);
|
// &(rec_datablock_free[i][j]));
|
||||||
}
|
// // printf("", rec_datablock_free[i][j]);
|
||||||
printf("\n");
|
// }
|
||||||
}
|
// // printf("\n");
|
||||||
|
// }
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
// for (int i = 0; i < 10; i++) {
|
||||||
printf("%dth data block allocate again addres: ", i);
|
// // printf("%dth data block allocate again addres: ", i);
|
||||||
for (int j = 0; j < 3; j++) {
|
// for (int j = 0; j < 3; j++) {
|
||||||
fs->allocate_datablock(&inode_list[i], &temp_block_num);
|
// fs->allocate_datablock(&inode_list[i], &temp_block_num);
|
||||||
//assert(temp_block_num == rec_datablock_free[i][j]);
|
// assert(temp_block_num == rec_datablock_free[i][j]);
|
||||||
printf("%llu," ,temp_block_num);
|
// // printf("%d," ,inode_inside[i].datablock_allocate(*H));
|
||||||
}
|
// }
|
||||||
printf("\n");
|
// // printf("\n");
|
||||||
}
|
// }
|
||||||
|
|
||||||
// printf("}\n");
|
// printf("}\n");
|
||||||
delete H; // Delete the RawDisk object
|
delete H; // Delete the RawDisk object
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#define FUSE_USE_VERSION 31
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -37,6 +39,10 @@ int total_file_num = 0;
|
|||||||
int total_free_dir = 0;
|
int total_free_dir = 0;
|
||||||
int total_free_file = 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) {
|
TEST(FileOperationTest, MkdirnodTest) {
|
||||||
|
|
||||||
fsop->initialize_rootinode();
|
fsop->initialize_rootinode();
|
||||||
@ -93,19 +99,19 @@ TEST(FileOperationTest, RamDiskTest) {
|
|||||||
FileNode* get_dir;
|
FileNode* get_dir;
|
||||||
u_int64_t get_disk_inum;
|
u_int64_t get_disk_inum;
|
||||||
|
|
||||||
get_dir = fischl_find_entry(fsop->root_node, "/test");//this is file
|
get_dir = fischl_load_entry(fsop->root_node, "/test");//this is file
|
||||||
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
||||||
EXPECT_STREQ(get_dir->name, "test");
|
EXPECT_STREQ(get_dir->name, "test");
|
||||||
get_disk_inum = fsop->disk_namei("/test");
|
get_disk_inum = fsop->disk_namei("/test");
|
||||||
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
|
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
|
||||||
|
|
||||||
get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/baz");//this is file
|
get_dir = fischl_load_entry(fsop->root_node, "/foo/bar/baz");//this is file
|
||||||
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
||||||
EXPECT_STREQ(get_dir->name, "baz");
|
EXPECT_STREQ(get_dir->name, "baz");
|
||||||
get_disk_inum = fsop->disk_namei("/foo/bar/baz");
|
get_disk_inum = fsop->disk_namei("/foo/bar/baz");
|
||||||
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
|
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
|
||||||
|
|
||||||
get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/..");
|
get_dir = fischl_load_entry(fsop->root_node, "/foo/bar/..");
|
||||||
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
||||||
EXPECT_STREQ(get_dir->name, "foo");
|
EXPECT_STREQ(get_dir->name, "foo");
|
||||||
ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory
|
ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory
|
||||||
@ -113,7 +119,7 @@ TEST(FileOperationTest, RamDiskTest) {
|
|||||||
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
|
EXPECT_EQ(get_disk_inum, get_dir->inode_number);
|
||||||
fsop->printDirectory(get_disk_inum);
|
fsop->printDirectory(get_disk_inum);
|
||||||
|
|
||||||
get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/.");
|
get_dir = fischl_load_entry(fsop->root_node, "/foo/bar/.");
|
||||||
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
EXPECT_TRUE(get_dir != NULL);//detect this should find success
|
||||||
EXPECT_STREQ(get_dir->name, "bar");
|
EXPECT_STREQ(get_dir->name, "bar");
|
||||||
ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory
|
ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory
|
||||||
|
Loading…
x
Reference in New Issue
Block a user