ハルビン工業大学(深圳)• 2024 • オペレーティングシステム Lab • における解決策 • HITSZ 操作系统实验 2024 基于FUSE的青春版EXT2文件系统
この部分は、xv6-oslab24-hitsz-answersから分離されたLab 5。
Lab 1 ~ 4を見たい方は下のボタンを押して下さい。
初期環境設定について
最初は、次の命令を入力して下さい
bash
cd ~
git clone https://gitee.com/ftutorials/user-land-filesystem.git
cd user-land-filesystem
chmod +x ./setenv.sh
chmod +x ./driver/ddriver.sh
./setenv.sh
#[指示を従って、環境を配置]
source ~/.bashrc
ddriver
#[ddriver interfaceが出た]
そのあと、demoのmain.c
を補完。demoで次のものを入力:
mkdir build
cmake -B . -S ..
cd build
この時、executableファイル(demo
)が出ない場合はmake
を実行でコードのエラーを一つずつ訂正でいい。
chiakiFSも同様、executableファイル(chiakiFS
)が出ない場合はmake
を実行でコードのエラーを一つずつ訂正でいい。
A Demo File System driven by ddriver
ddriverの紹介
Interface Function | Description |
---|---|
int ddriver_open (char* path) | 指定されたパス path に基づいて仮想ディスクを開き、ファイルディスクリプタ fd を返します。path は固定で ~/ddriver の絶対パスを指定する必要があります。 |
int ddriver_close (int fd) | 開かれた仮想ディスクを閉じます。 |
int ddriver_seek (int fd, off_t offset, int whence) | 基準となる whence とオフセット offset に基づいて仮想ディスクのディスクヘッドを移動します。whence の基準は通常 SEEK_SET (つまり 0)に固定され、オフセット offset を指定します。 |
int ddriver_read (int fd, char* buf, size_t size) | I/O サイズに従って仮想ディスクからデータを読み込みます。size は I/O サイズに固定して指定する必要があり。 |
int ddriver_write (int fd, char* buf, size_t size) | I/O サイズに従って仮想ディスクにデータを書き込みます。size は I/O サイズに固定して指定する必要があり。 |
int ddriver_ioctl (int fd, unsigned long cmd, void* ret) | 指定されたコマンド cmd に基づいて仮想ディスクの情報を取得します。cmd が IOC_REQ_DEVICE_SIZE の場合、void *ret には仮想ディスクの総サイズが返されます。cmd が IOC_REQ_DEVICE_IO_SZ の場合、void *ret には仮想ディスクの I/O サイズが返されます。 |
1. スーパーブロックの設定
int sz_io; /* ディスクIOサイズ(単位:バイト) */
int sz_disk; /* ディスク容量(単位:バイト) */
int sz_blks; /* 論理ブロックサイズ(単位:バイト) */
まずは、この3つのフィールドを設定。
この部分のコードは、super
構造体に必要な情報を設定して、シミュレーションされたディスクの詳細(IOサイズ、ディスクサイズ、ブロックサイズ)を取得する処理です。それぞれの行を詳細に説明します。
ddriver_ioctl(super.driver_fd, IOC_REQ_DEVICE_IO_SZ, &super.sz_io);
ddriver_ioctl(super.driver_fd, IOC_REQ_DEVICE_SIZE, &super.sz_disk);
super.sz_blks = 2 * super.sz_io;
ddriver_ioctl
は、デバイスドライバに対して特定の制御操作を行うための関数です。IOC_REQ_DEVICE_IO_SZ
は「デバイスの I/O サイズを要求する」という操作コードです。super.driver_fd
はデバイスファイルのファイルディスクリプタで、どのデバイスに対して操作を行うかを示します。&super.sz_io
は、取得した I/O サイズ(1回のデータ転送の単位サイズ)を格納するためのポインタです。IOC_REQ_DEVICE_SIZE
は「デバイスの総ディスクサイズを要求する」という操作コードです。&super.sz_disk
は、取得したディスクサイズ(総容量、単位:バイト)を格納するためのポインタです。super.sz_blks
は論理ブロックのサイズ。- この部分では、1ブロックが I/O サイズの2倍であると仮定しています。従って、
super.sz_io
を2倍した値をsuper.sz_blks
に代入しています。
2. 特定なディスクオフセットへ移動
off_t disk_offset = 500 * super.sz_blks;
ddriver_seek(super.driver_fd, disk_offset, SEEK_SET);
ここでは、ディスク上の500番目の論理ブロックのオフセットを計算する必要があります。ブロックのサイズは super.sz_blks
ですので、500番目の論理ブロックのオフセットは 500 * super.sz_blks
になります。その後、ddriver_seek
を使って、ファイルディスクリプタ super.driver_fd
の位置をそのオフセットに移動します。SEEK_SET
はファイルの先頭からオフセットを指定する意味です。
3. ディスクブロックを読込
3. ディスクブロックを読み取る
char block[super.sz_io];
ddriver_read(super.driver_fd, block, super.sz_io);
ddriver_read
は、指定したサイズのデータをディスクから読み取るために使用します。ここでは、block
というバッファにデータを格納する準備をしています。このバッファのサイズは、ディスクの I/O サイズ super.sz_io
に基づいています。ddriver_read
は、super.driver_fd
から super.sz_io
バイトを読み取り、その内容を block
配列に格納します。
4. 先のブロックからdemo_dentry
を取得
struct demo_dentry entry;
memcpy(&entry, block, sizeof(struct demo_dentry));
ここでは、読み取ったディスクブロックのデータを demo_dentry
構造体にコピーしています。具体的には、block
の先頭から sizeof(struct demo_dentry)
バイトを entry
という構造体にコピーします。demo_dentry
はファイル名(fname
)を格納する構造体で、これを使ってディスクブロックからファイル名などの情報を抽出します。
5. ファイル名を設定する
strncpy(filename, entry.fname, sizeof(filename) - 1);
filename[sizeof(filename) - 1] = '\0';
entry.fname
には、ディスクブロックから読み取ったファイル名が格納されています。このファイル名を filename
配列にコピーするために strncpy
を使います。sizeof(filename) - 1
は、配列の末尾に \0
を追加するための余地を残すためです。最後に、filename
配列の末尾に \0
を手動で追加することで、文字列として正しく終了するようにします。
6. 通常ファイルとして表示するための属性設定
stbuf->st_mode = DEMO_DEFAULT_PERM | S_IFREG;
st_mode
はファイルの属性を表すフィールドで、ファイルのタイプとアクセス権限を示します。DEMO_DEFAULT_PERM
はデフォルトのアクセス権限(0777:-rwxrwxrwx)で、読み書き実行権限を全てのユーザに与えています。S_IFREG
は、通常のファイルを示す定数です。これにより、st_mode
が「通常ファイル」の属性を持つように設定されます。
この部分は、サンプルコードでコード補完でいい。
#define _XOPEN_SOURCE 700
#define FUSE_USE_VERSION 26
#include "stdio.h"
#include "fuse.h"
#include "../include/ddriver.h"
#include <linux/fs.h>
#include "pwd.h"
#include "unistd.h"
#include "string.h"
#define DEMO_DEFAULT_PERM 0777
/* スーパーブロック */
struct demo_super
{
int driver_fd; /* シミュレートされたディスクのファイルディスクリプタ */
int sz_io; /* ディスクIOサイズ(単位:バイト) */
int sz_disk; /* ディスク容量(単位:バイト) */
int sz_blks; /* 論理ブロックサイズ(単位:バイト) */
};
/* ディレクトリエントリ */
struct demo_dentry
{
char fname[128];
};
struct demo_super super;
#define DEVICE_NAME "ddriver"
/* ファイルシステムのマウント */
static void* demo_mount(struct fuse_conn_info * conn_info){
// ドライバを開く
char device_path[128] = {0};
sprintf(device_path, "%s/" DEVICE_NAME, getpwuid(getuid())->pw_dir);
super.driver_fd = ddriver_open(device_path);
printf("super.driver_fd: %d\n", super.driver_fd);
/* super情報を設定 */
ddriver_ioctl(super.driver_fd, IOC_REQ_DEVICE_IO_SZ, &super.sz_io); /* TODO */;
ddriver_ioctl(super.driver_fd, IOC_REQ_DEVICE_SIZE, &super.sz_disk); /* TODO */;
super.sz_blks = 2 * super.sz_io; /* TODO */;
return 0;
}
/* ファイルシステムのアンマウント */
static void demo_umount(void* p){
// ドライバを閉じる
ddriver_close(super.driver_fd);
}
/* ディレクトリの読み取り */
static int demo_readdir(const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi)
{
// この部分では、引数の詳細を気にせず、そして使わない。demo_readdir内で設定したパラメータだけを使用してください
char filename[128]; // 設定すべきファイル名
/* スーパーブロックの情報に基づき、500番目の論理ブロックからdentryを読み込む。lsはこのファイル名だけを表示します */
/* TODO: ディスクのオフセットを計算し、そのオフセットに基づいてddriver_seekでディスクヘッドをオフセットに移動 */
off_t disk_offset = 500 * super.sz_blks;
ddriver_seek(super.driver_fd, disk_offset, SEEK_SET);
/* TODO: ddriver_readを使ってディスクブロックをメモリに読み込む(512バイト) */
char block[super.sz_io];
ddriver_read(super.driver_fd, block, super.sz_io);
/* TODO: memcpyを使って、先ほどの512バイトの前sizeof(demo_dentry)バイトをdemo_dentry構造体にコピー */
struct demo_dentry entry;
memcpy(&entry, block, sizeof(struct demo_dentry));
/* TODO: filenameを設定 */
strncpy(filename, entry.fname, sizeof(filename) - 1);
filename[sizeof(filename) - 1] = '\0';
// この部分ではfillerを気にしないでください。fillerはすでに設定されているので、filenameを設定するだけでOKです
return filler(buf, filename, NULL, 0);
}
/* ファイルの属性を表示 */
static int demo_getattr(const char* path, struct stat *stbuf)
{
if(strcmp(path, "/") == 0)
stbuf->st_mode = DEMO_DEFAULT_PERM | S_IFDIR; // ルートディレクトリはディレクトリファイル
else
/* TODO: 通常のファイルとして表示 */
stbuf->st_mode = DEMO_DEFAULT_PERM | S_IFREG; // このファイルは通常のファイルとして表示
return 0;
}
/* 要求に基づき、ls操作を完了するためには最初の4つのフック関数を実装するだけでよい */
static struct fuse_operations ops = {
.init = demo_mount, /* ファイルシステムのマウント */
.destroy = demo_umount, /* ファイルシステムのアンマウント */
.getattr = demo_getattr, /* ファイル属性の取得 */
.readdir = demo_readdir, /* dentryの設定 */
};
int main(int argc, char *argv[])
{
int ret = 0;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
ret = fuse_main(args.argc, args.argv, &ops, NULL);
fuse_opt_free_args(&args);
return ret;
}
chiakiFS : A simplified EXT2 file system on FUSE
ファイルシステムの基本On-Diskレイアウト
On-Disk構造は、type.hで定義された。
/******************************************************************************
* SECTION: FS Specific Structure - Disk structure (ファイルシステム固有構造 - ディスク構造)
*******************************************************************************/
struct chiakiFS_super_d // 40B
{
uint32_t magic_num; // マジックナンバー
uint32_t sz_usage; // 使用サイズ
uint32_t max_ino; // 最大inode数
uint32_t map_inode_blks; // inodeマップブロック数
uint32_t map_inode_offset; // inodeマップオフセット
uint32_t inode_offset; // inodeオフセット
uint32_t max_data; // 最大データ数
uint32_t map_data_blks; // データマップブロック数
uint32_t map_data_offset; // データマップオフセット
uint32_t data_offset; // データオフセット
};
struct chiakiFS_inode_d // 164B
{
uint32_t ino; // inodeビットマップのインデックス, 4B
uint32_t size; // ファイル使用領域サイズ, 4B
char target_path[CHIAKIFS_MAX_FILE_NAME]; // シンボリックリンク時のターゲットパス, 128*1B
uint32_t dir_cnt; // ディレクトリカウント, 4B
uint32_t link_cnt; // リンク数, 4B
CHIAKIFS_FILE_TYPE ftype; // ファイルタイプ, 4B
int dblk[CHIAKIFS_DATA_PER_FILE]; // データブロック番号, 4*4B
};
struct chiakiFS_dentry_d // 136B
{
char fname[CHIAKIFS_MAX_FILE_NAME]; // ファイル名
CHIAKIFS_FILE_TYPE ftype; // ファイルタイプ
uint32_t ino; // 指定されたinode番号
};
各Inodeには、データブロックを指す4つのポインタが割り当てられます。このとき、chiakiFS_inode_dのサイズは164Bであり、各ファイルが必要とする最大サイズは$4\times 1024 + 164 =4260$ Bとなります。また、1つの索引ブロックには$1024/164=6.2$、即ち6つの索引ノードが格納可能です。
ファイルシステム全体のサイズは4MBで、各論理ブロックのサイズは1024Bです。したがって、合計で4K個のブロックが存在します。このうち、スーパーブロック、索引ノードビットマップ、データブロックビットマップがそれぞれ1つの論理ブロックを占有します。残りのスペースはファイルの保存に使用されます。また、各索引ブロックには40Bの未使用領域があるため、このスペースを各索引ノードに均等に割り当てます。この結果、各索引ノードのサイズは171Bとみなされます。この場合、ファイルシステムには最大で$(4M-3K)/4267=982.24$、すなわち982個のファイルが収容可能です。
したがって、索引ノードの保存には$982\div 6=163.67$、すなわち164個の索引ブロックが必要です。このとき、データブロックの数は$4096-1-1-1-164=3929$となります。

以下は具体的なOn-Disk設計案の概略図です。これにはスーパーブロックなどの内部構造が含まれています。しかし、ここで強調したいのは、実際のコード実装においては、ディスクにDentryを書き込む方向が逆であるという点です。つまり、下図では最初に有効なDentry(Dentry4)がデータブロック0に書き込まれ、その後Dentry3などが書き込まれます。そのため、この図のディスクレイアウトは実際の実装とは若干異なります。更に、ファイルシステムをマウントすると、この4MBのファイルシステムは仮想アドレス上でスタック領域に割り当てられ、下方向に成長し。したがって、この図はあくまで参考用。

ファイルシステムの基本In-Memレイアウト
ディスクの内容をメモリに読み込んだ後、具体的なinode、dentry、およびスーパーブロックの構造にいくつかの変更が生じます。以下の定義とIn-Mem構造図を参照してください。
/******************************************************************************
* SECTION: FS Specific Structure - In memory structure (ファイルシステム固有構造 - メモリ内構造)
*******************************************************************************/
struct chiakiFS_inode
{
int ino; // inode番号
int size; // ファイル使用領域サイズ
char target_path[CHIAKIFS_MAX_FILE_NAME]; // シンボリックリンク時のターゲットパス
int dir_cnt; // ディレクトリカウント
uint32_t link_cnt; // リンク数
struct chiakiFS_dentry* dentry; // このinodeへのdentryへのポインタ
struct chiakiFS_dentry* dentrys; // 全てのディレクトリエントリ
uint8_t* data[CHIAKIFS_DATA_PER_FILE]; // データブロック
int dblk[CHIAKIFS_DATA_PER_FILE]; // データブロック番号
};
struct chiakiFS_dentry
{
char fname[CHIAKIFS_MAX_FILE_NAME];// ファイル名
struct chiakiFS_dentry* parent; // 親inodeのdentry
struct chiakiFS_dentry* brother; // 兄弟dentry
int ino; // inode番号
struct chiakiFS_inode* inode; // inodeへのポインタ
CHIAKIFS_FILE_TYPE ftype; // ファイルタイプ
};
struct chiakiFS_super
{
int driver_fd; // ドライバファイルディスクリプタ
int sz_io; // IOサイズ
int sz_disk; // ディスクサイズ
int sz_blk; // ブロックサイズ
int sz_usage; // 使用サイズ
int max_ino; // 最大inode数
uint8_t* map_inode; // inodeマップ
int map_inode_blks; // inodeマップブロック数
int map_inode_offset; // inodeマップオフセット
int inode_offset; // inodeオフセット
int max_data; // 最大データ数
uint8_t* map_data; // データマップ
int map_data_blks; // データマップブロック数
int map_data_offset; // データマップオフセット
int data_offset; // データオフセット
boolean is_mounted; // マウント状態
struct chiakiFS_dentry* root_dentry; // ルートdentryへのポインタ
};
In-Mem表現では、アドレスは表示されません。図に示されている各モジュールの内部構造は、モジュール内にそのような構造が存在することを反映しているだけで、アドレスや順序に関連する情報は反映していません。ポインタの種類は色で区別されています。破線はヌルポインタを表します。最下部の破線は省略記号です。

マクロ定義
ファイルシステムを実現するためには、いくつかの特殊な定数や関数を定義して再利用しやすくする必要があります。
/******************************************************************************
* SECTION: Macro (マクロ定義セクション)
*******************************************************************************/
#define TRUE 1
#define FALSE 0
#define UINT32_BITS 32
#define UINT8_BITS 8
#define CHIAKIFS_SUPER_OFS 0 // スーパーブロックのオフセット
#define CHIAKIFS_ROOT_INO 0 // ルートinode番号
// Layout用マクロ
#define CHIAKIFS_SUPER_BLKS 1 // スーパーブロックのブロック数
#define CHIAKIFS_MAP_INODE_BLKS 1 // inodeマップのブロック数
#define CHIAKIFS_MAP_DATA_BLKS 1 // データマップのブロック数
#define CHIAKIFS_INODE_PER_BLOCK 6 // ブロックごとのinode数 (Layout)
#define CHIAKIFS_INODE_BLKS 164 // inodeのブロック数
#define CHIAKIFS_DATA_BLKS 3929 // データブロックの数
#define CHIAKIFS_MAX_FILE_NAME 128 // ファイル名の最大長さ
#define CHIAKIFS_INODE_PER_FILE 1 // ファイルごとのinode数 (Layout)
#define CHIAKIFS_DATA_PER_FILE 4 // ファイルごとのデータブロック数 (Layout)
#define CHIAKIFS_DEFAULT_PERM 0777 // デフォルトのパーミッション -rwxrwxrwx
#define CHIAKIFS_IOC_MAGIC 'S' // IOCTLのマジック
#define CHIAKIFS_IOC_SEEK _IO(CHIAKIFS_IOC_MAGIC, 0) // IOCTL SEEK
// バッファのフラグ定義
#define CHIAKIFS_FLAG_BUF_DIRTY 0x1 // バッファがダーティ状態
#define CHIAKIFS_FLAG_BUF_OCCUPY 0x2 // バッファが使用中
/******************************************************************************
* SECTION: Macro Function (マクロ関数セクション)
*******************************************************************************/
#define CHIAKIFS_IO_SZ() (chiakiFS_super.sz_io) // IOサイズ取得
#define CHIAKIFS_DISK_SZ() (chiakiFS_super.sz_disk) // ディスクサイズ取得
#define CHIAKIFS_BLK_SZ() (chiakiFS_super.sz_blk) // ブロックサイズ取得
#define CHIAKIFS_DRIVER() (chiakiFS_super.driver_fd) // ドライバ取得
#define CHIAKIFS_DENTRY_PER_DATABLK() (CHIAKIFS_BLK_SZ()/sizeof(struct chiakiFS_dentry)) // データブロックごとのdentry数
#define CHIAKIFS_ROUND_DOWN(value, round) ((value) % (round) == 0 ? (value) : ((value) / (round)) * (round))
#define CHIAKIFS_ROUND_UP(value, round) ((value) % (round) == 0 ? (value) : ((value) / (round) + 1) * (round))
#define CHIAKIFS_BLKS_SZ(blks) ((blks) * CHIAKIFS_BLK_SZ()) // ブロック数からサイズ取得
#define CHIAKIFS_ASSIGN_FNAME(pchiakiFS_dentry, _fname) \
do { \
strncpy((pchiakiFS_dentry)->fname, (_fname), CHIAKIFS_MAX_FILE_NAME - 1); \
(pchiakiFS_dentry)->fname[CHIAKIFS_MAX_FILE_NAME - 1] = '\0'; \
} while(0)
// ファイル名の割り当て
#define CHIAKIFS_INO_OFS(ino) (chiakiFS_super.inode_offset \
+ (ino / CHIAKIFS_INODE_PER_BLOCK) * CHIAKIFS_BLK_SZ() \
+ (ino % CHIAKIFS_INODE_PER_BLOCK) * sizeof(struct chiakiFS_inode_d)) // inodeオフセット計算
#define CHIAKIFS_DATA_OFS(dno) (chiakiFS_super.data_offset + CHIAKIFS_BLKS_SZ(dno)) // データオフセット計算
// inodeのタイプをチェックするマクロ
#define CHIAKIFS_IS_DIR(pinode) (pinode->dentry->ftype == CHIAKIFS_DIR)
#define CHIAKIFS_IS_REG(pinode) (pinode->dentry->ftype == CHIAKIFS_REG_FILE)
#define CHIAKIFS_IS_SYM_LINK(pinode) (pinode->dentry->ftype == CHIAKIFS_SYM_LINK)
マクロ定数
- 論理値の定義
TRUE
: 論理値1
を定義FALSE
: 論理値0
を定義
- ビット数の定義
UINT32_BITS
: 32ビット整数のビット数 (32
)UINT8_BITS
: 8ビット整数のビット数 (8
)
- ファイルシステムのオフセットと初期設定
CHIAKIFS_SUPER_OFS
: スーパーブロックのオフセット(0
)CHIAKIFS_ROOT_INO
: ルートinode番号(0
)
- レイアウト用定義
CHIAKIFS_SUPER_BLKS
: スーパーブロックのブロック数(1
)CHIAKIFS_MAP_INODE_BLKS
: inodeマップのブロック数(1
)CHIAKIFS_MAP_DATA_BLKS
: データマップのブロック数(1
)CHIAKIFS_INODE_PER_BLOCK
: ブロックごとのinode数(6
)CHIAKIFS_INODE_BLKS
: inodeのブロック数(164
)CHIAKIFS_DATA_BLKS
: データブロックの数(3929
)
- ファイルシステムに関連するパラメータ
CHIAKIFS_MAX_FILE_NAME
: ファイル名の最大長さ(128
)CHIAKIFS_INODE_PER_FILE
: ファイルごとのinode数(1
)CHIAKIFS_DATA_PER_FILE
: ファイルごとのデータブロック数(4
)CHIAKIFS_DEFAULT_PERM
: デフォルトのパーミッション(0777
)
- IOCTL関連の定義
CHIAKIFS_IOC_MAGIC
: IOCTLのマジック番号('S'
)CHIAKIFS_IOC_SEEK
: IOCTLでのSEEK操作を定義するためのマクロ
- バッファフラグの定義
CHIAKIFS_FLAG_BUF_DIRTY
: バッファがダーティ状態であることを示すフラグ(0x1
)CHIAKIFS_FLAG_BUF_OCCUPY
: バッファが使用中であることを示すフラグ(0x2
)
マクロ関数
- ファイルシステムの基本情報を取得するためのマクロ
CHIAKIFS_IO_SZ()
: IOサイズの取得CHIAKIFS_DISK_SZ()
: ディスクサイズの取得CHIAKIFS_BLK_SZ()
: ブロックサイズの取得CHIAKIFS_DRIVER()
: ドライバの取得CHIAKIFS_DENTRY_PER_DATABLK()
: データブロックあたりのdentry数の取得
- 丸め
CHIAKIFS_ROUND_DOWN(value, round)
:value
をround
の倍数に丸める(切下)CHIAKIFS_ROUND_UP(value, round)
:value
をround
の倍数に丸める(切上)
- ブロック数からサイズを計算するマクロ
CHIAKIFS_BLKS_SZ(blks)
: 指定されたブロック数 (blks
) からサイズを計算
- ファイル名の割り当て
CHIAKIFS_ASSIGN_FNAME(pchiakiFS_dentry, _fname)
: 指定されたfname
をpchiakiFS_dentry
に割り当て(ファイル名をコピー)
- オフセット計算
CHIAKIFS_INO_OFS(ino)
: 指定されたinodeのオフセットを計算CHIAKIFS_DATA_OFS(dno)
: 指定されたデータブロックのオフセットを計算
- inodeのタイプチェック
CHIAKIFS_IS_DIR(pinode)
:pinode
がディレクトリかどうかをチェックCHIAKIFS_IS_REG(pinode)
:pinode
が通常ファイルかどうかをチェックCHIAKIFS_IS_SYM_LINK(pinode)
:pinode
がシンボリックリンクかどうかをチェック
エラー定数
ここは、幾つのエラー定数を定義し。
// エラーコードのマクロ定義
#define CHIAKIFS_ERROR_NONE 0 // エラーなし
#define CHIAKIFS_ERROR_ACCESS EACCES // アクセスエラー
#define CHIAKIFS_ERROR_SEEK ESPIPE // シークエラー
#define CHIAKIFS_ERROR_ISDIR EISDIR // ディレクトリエラー
#define CHIAKIFS_ERROR_NOSPACE ENOSPC // スペース不足エラー
#define CHIAKIFS_ERROR_EXISTS EEXIST // ファイルが既に存在するエラー
#define CHIAKIFS_ERROR_NOTFOUND ENOENT // ファイルが見つからないエラー
#define CHIAKIFS_ERROR_UNSUPPORTED ENXIO // サポートされていないエラー
#define CHIAKIFS_ERROR_IO EIO // 入出力エラー
#define CHIAKIFS_ERROR_INVAL EINVAL // 無効な引数エラー
#define CHIAKIFS_ERROR_NOTDIR ENOTDIR // ディレクトリではないエラー
Low Level 関数デザイン
Low Level関数一覧:
/******************************************************************************
* SECTION: chiakiFS_utils.c
*******************************************************************************/
char* chiakiFS_get_fname(const char* path);
int chiakiFS_calc_lvl(const char * path);
int chiakiFS_driver_read(int offset, uint8_t *out_content, int size);
int chiakiFS_driver_write(int offset, uint8_t *in_content, int size);
int chiakiFS_mount(struct custom_options options);
int chiakiFS_umount();
int chiakiFS_alloc_dentry(struct chiakiFS_inode * inode, struct chiakiFS_dentry * dentry, int W);
int chiakiFS_drop_dentry(struct chiakiFS_inode * inode, struct chiakiFS_dentry * dentry);
struct chiakiFS_inode* chiakiFS_alloc_inode(struct chiakiFS_dentry * dentry);
int chiakiFS_sync_inode(struct chiakiFS_inode * inode);
int chiakiFS_drop_inode(struct chiakiFS_inode * inode);
struct chiakiFS_inode* chiakiFS_read_inode(struct chiakiFS_dentry * dentry, int ino);
struct chiakiFS_dentry* chiakiFS_get_dentry(struct chiakiFS_inode * inode, int dir);
struct chiakiFS_dentry* chiakiFS_lookup(const char * path, boolean * is_find, boolean* is_root);
便利のため、new_dentryをtypes.hでinline関数として実装
// 新しいdentryを作成する関数
static inline struct chiakiFS_dentry* new_dentry(char * fname, CHIAKIFS_FILE_TYPE ftype) {
struct chiakiFS_dentry * dentry = (struct chiakiFS_dentry *)malloc(sizeof(struct chiakiFS_dentry));
memset(dentry, 0, sizeof(struct chiakiFS_dentry));
CHIAKIFS_ASSIGN_FNAME(dentry, fname);
dentry->ftype = ftype;
dentry->ino = -1;
dentry->inode = NULL;
dentry->parent = NULL;
dentry->brother = NULL;
return dentry;
}
chiakiFS_get_fname
指定されたパスからファイル名を抽出します。
/**
* @brief ファイル名を取得
*
* @param path
* @return char*
*/
char *chiakiFS_get_fname(const char *path)
{
char ch = '/';
char *q = strrchr(path, ch);
if (q == NULL)
return (char *)path;
else
return q + 1;
}
strrchr
関数を使用して、パスの中で最後の '/'
の位置を探します。その位置に 1 を加えて、ファイル名の先頭文字のポインタを取得します。尚、パスの中で最後の '/'
が存在しない場合(ルートディレクトリのパス)、パスをそのままreturn.
chiakiFS_calc_lvl
パスの深さを計算します。
/**
* @brief パスの深さを計算
* exm: /av/c/d/f
* -> lvl = 4
* @param path
* @return int
*/
int chiakiFS_calc_lvl(const char *path)
{
// char* path_cpy = (char *)malloc(strlen(path));
// strcpy(path_cpy, path);
char *str = path;
int lvl = 0;
if (strcmp(path, "/") == 0)
{
return lvl;
}
while (*str != NULL)
{
if (*str == '/')
{
lvl++;
}
str++;
}
return lvl;
}
文字列の先頭から末尾までを走査します。毎回 '/'
を見つけるたびに階層を 1 増加させます。もしパスがルートパス '/'
であれば、階層は 0 です。
chiakiFS_driver_read
指定されたオフセット位置からデータを読み取り、指定されたサイズのデータを出力バッファに保存します。
/**
* @brief ddriver読込
*
* @param offset オフセット(読み込み開始位置)
* @param out_content 読み込んだ内容を格納するバッファ
* @param size 読み込むデータのサイズ
* @return int 成功時は0(CHIAKIFS_ERROR_NONE)を返す
*/
int chiakiFS_driver_read(int offset, uint8_t *out_content, int size)
{
int offset_aligned = CHIAKIFS_ROUND_DOWN(offset, CHIAKIFS_BLK_SZ()); // ロジカルブロックにアライン
int bias = offset - offset_aligned; // アラインされたオフセットとの差分
int size_aligned = CHIAKIFS_ROUND_UP((size + bias), CHIAKIFS_BLK_SZ()); // 読み込むサイズをブロック単位にアライン
uint8_t *temp_content = (uint8_t *)malloc(size_aligned); // 一時的にデータを格納するためのバッファを確保
uint8_t *cur = temp_content; // 現在の読み込み位置を指すポインタ
// lseek(CHIAKIFS_DRIVER(), offset_aligned, SEEK_SET);
ddriver_seek(CHIAKIFS_DRIVER(), offset_aligned, SEEK_SET); // 読み込み位置を設定
while (size_aligned != 0)
{
// read(CHIAKIFS_DRIVER(), cur, CHIAKIFS_IO_SZ());
ddriver_read(CHIAKIFS_DRIVER(), cur, CHIAKIFS_IO_SZ()); // データを読み込む
cur += CHIAKIFS_IO_SZ(); // ポインタを次の読み込み位置に進める
size_aligned -= CHIAKIFS_IO_SZ(); // 残りのサイズを減らす
}
memcpy(out_content, temp_content + bias, size); // 必要な部分だけをout_contentにコピー
free(temp_content); // 一時バッファの解放
return CHIAKIFS_ERROR_NONE; // エラーなしを返す
}
読み取り開始位置とサイズを調整し、ブロックサイズに合わせてアライメントを取り。一時バッファを割当、I/O ブロック単位でデータを読み込みます。調整前のオフセットを考えで、実際に必要なデータ部分のみを出力バッファ(out_content
)にコピーします。んで一時バッファを解放でいい。
chiakiFS_driver_write
指定されたオフセット位置からデータを書き込みます。
/**
* @brief ddriver書込
*
* @param offset オフセット(書き込み開始位置)
* @param in_content 書き込む内容が格納されたバッファ
* @param size 書き込むデータのサイズ
* @return int 成功時はエラーコードCHIAKIFS_ERROR_NONEを返す
*/
int chiakiFS_driver_write(int offset, uint8_t *in_content, int size)
{
int offset_aligned = CHIAKIFS_ROUND_DOWN(offset, CHIAKIFS_BLK_SZ());
int bias = offset - offset_aligned;
int size_aligned = CHIAKIFS_ROUND_UP((size + bias), CHIAKIFS_BLK_SZ());
uint8_t *temp_content = (uint8_t *)malloc(size_aligned);
uint8_t *cur = temp_content;
chiakiFS_driver_read(offset_aligned, temp_content, size_aligned); // 既存データをtemp_contentに読み込む
memcpy(temp_content + bias, in_content, size); // 新しいデータを必要な位置にコピー
// lseek(CHIAKIFS_DRIVER(), offset_aligned, SEEK_SET);
ddriver_seek(CHIAKIFS_DRIVER(), offset_aligned, SEEK_SET); // 書き込み位置を設定
while (size_aligned != 0)
{
// write(CHIAKIFS_DRIVER(), cur, CHIAKIFS_IO_SZ());
ddriver_write(CHIAKIFS_DRIVER(), cur, CHIAKIFS_IO_SZ()); // データを書き込む
cur += CHIAKIFS_IO_SZ(); // ポインタを次の書き込み位置に進める
size_aligned -= CHIAKIFS_IO_SZ(); // 残りのサイズを減らす
}
free(temp_content); // バッファ解放
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_driver_readと同じ、書き込み開始位置とサイズを調整し、ブロックサイズに合わせてアライメントを取ります。現在のデータから一時バッファに読み込みます。オフセットを考えで、新しいデータを一時バッファの適切な位置にコピーします。一時バッファのデータをデバイスに書き戻します。んで一時バッファを解放でいい。
chiakiFS_alloc_dentry
指定された inode のために dentry を割り当て、必要に応じて新しいデータブロックを割り当てます。
/**
* @brief inodeにdentryを分配する
*
* @param inode 分配先のinode構造体
* @param dentry 分配するdentry構造体
* @param W 書き込みが必要かを示すフラグ
* @return int 更新されたディレクトリのカウント
*/
int chiakiFS_alloc_dentry(struct chiakiFS_inode *inode, struct chiakiFS_dentry *dentry, boolean W)
{
if (inode->dentrys == NULL)
{
inode->dentrys = dentry; // dentrysがNULLの場合、新しいdentryを設定
}
else
{
dentry->brother = inode->dentrys; // 既存のdentryの前に新しいdentryを挿入
inode->dentrys = dentry;
}
inode->dir_cnt++; // ディレクトリエントリ数を増加
int cur_blk = inode->dir_cnt / CHIAKIFS_DENTRY_PER_DATABLK(); // 現在のブロック位置を計算
if (W)
{ // 書き込みが必要か確認
if (inode->dir_cnt % CHIAKIFS_DENTRY_PER_DATABLK() == 1)
{
int byte_cursor = 0;
int bit_cursor = 0;
int dno_cursor = 0;
boolean is_find_free_blk = FALSE;
for (byte_cursor = 0; byte_cursor < CHIAKIFS_BLKS_SZ(chiakiFS_super.map_data_blks); byte_cursor++)
{
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++)
{
if ((chiakiFS_super.map_data[byte_cursor] & (0x1 << bit_cursor)) == 0)
{
/* 現在のdno_cursor位置が空き */
chiakiFS_super.map_data[byte_cursor] |= (0x1 << bit_cursor); // 該当ビットを1に設定
inode->dblk[cur_blk] = dno_cursor; // inodeにブロック番号を設定
is_find_free_blk = TRUE; // 空きブロックが見つかったとフラグを立てる
break;
}
dno_cursor++; // データブロック番号を進める
}
if (is_find_free_blk)
{
break; // 空きブロックが見つかったらループを抜ける
}
}
// 空きデータブロックが見つからない場合
if (!is_find_free_blk || dno_cursor == chiakiFS_super.max_data)
return -CHIAKIFS_ERROR_NOSPACE;
}
}
return inode->dir_cnt; // ディレクトリカウントを返す
}
dentry を inode の dentry リストに追加します。ディレクトリエントリ数を更新します。書き込みフラグ W
が設定されている場合、新しいデータブロックが必要かどうかを確認します。新しいブロックが必要な場合、データブロックのビットマップから空きブロックを検索し、割当。割り当てたブロック番号を inode に設定します。
chiakiFS_drop_dentry
指定された inode から特定の dentry を削除します。
/**
* @brief inodeのdentrysからdentryを取り除く
*
* @param inode 対象のinode構造体
* @param dentry 削除するdentry構造体
* @return int 成功時は更新されたディレクトリカウントを返し、見つからない場合はエラーコードを返す
*/
int chiakiFS_drop_dentry(struct chiakiFS_inode *inode, struct chiakiFS_dentry *dentry)
{
boolean is_find = FALSE;
struct chiakiFS_dentry *prev_dentry = NULL; // 前のdentryを指すポインタ
struct chiakiFS_dentry *dentry_cursor = inode->dentrys; // 現在のdentryを指すポインタ
while (dentry_cursor)
{ // dentryリストを巡回
if (dentry_cursor == dentry)
{
if (prev_dentry == NULL)
{
// 削除対象のdentryがリストの最初の場合
inode->dentrys = dentry_cursor->brother;
}
else
{
prev_dentry->brother = dentry_cursor->brother; // リストのリンクを更新
}
is_find = TRUE;
break;
}
prev_dentry = dentry_cursor;
dentry_cursor = dentry_cursor->brother; // 次のdentryに進む
}
if (!is_find)
{
return -CHIAKIFS_ERROR_NOTFOUND; // dentryが見つからない場合、エラーを返す
}
inode->dir_cnt--; // ディレクトリのカウントを減らす
return inode->dir_cnt;
}
inode の dentry リストを走査し、目的の dentry を見つけます。リストからその dentry を削除し、dentry リストを再リンクします。ディレクトリエントリ数を更新します。目的の dentry が見つからない場合、エラーを返します。
chiakiFS_alloc_inode
新しい inode を割り当て、関連するビットマップを更新します。
/**
* @brief inodeを分配,ビットマップを設置
*
* @param dentry dentry→このinode
* @return chiakiFS_inode 成功時は新しいinodeを返し、失敗時はエラーコードを返す
*/
struct chiakiFS_inode *chiakiFS_alloc_inode(struct chiakiFS_dentry *dentry)
{
struct chiakiFS_inode *inode;
int byte_cursor = 0;
int bit_cursor = 0;
int ino_cursor = 0;
int dblk_cursor = 0;
boolean is_find_free_entry = FALSE;
for (byte_cursor = 0; byte_cursor < CHIAKIFS_BLKS_SZ(chiakiFS_super.map_inode_blks);
byte_cursor++)
{
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++)
{
if ((chiakiFS_super.map_inode[byte_cursor] & (0x1 << bit_cursor)) == 0)
{
/* ino_cursorの位置が空*/
chiakiFS_super.map_inode[byte_cursor] |= (0x1 << bit_cursor); // 空きinodeを確保
is_find_free_entry = TRUE;
break;
}
ino_cursor++; // inodeカーソルを進める
}
if (is_find_free_entry)
{
break; // 空きinodeが見つかったらループを抜ける
}
}
if (!is_find_free_entry || ino_cursor == chiakiFS_super.max_ino)
return (void *)-CHIAKIFS_ERROR_NOSPACE; // 空きinodeがない場合はエラーを返す
inode = (struct chiakiFS_inode *)malloc(sizeof(struct chiakiFS_inode)); // inode構造体のメモリを確保
inode->ino = ino_cursor;
inode->size = 0;
inode->dir_cnt = 0;
inode->dentrys = 0;
/* dentry→inode */
dentry->inode = inode;
dentry->ino = inode->ino;
/* inode→dentry */
inode->dentry = dentry;
inode->dir_cnt = 0;
inode->dentrys = NULL;
if (CHIAKIFS_IS_DIR(inode))
inode -> link_cnt = 2;
else
inode -> link_cnt = 1;
if (CHIAKIFS_IS_REG(inode))
{ // レギュラーファイルの場合
for (int i = 0; i < CHIAKIFS_DATA_PER_FILE; i++)
inode->data[i] = (uint8_t *)malloc(CHIAKIFS_BLK_SZ()); // データブロックのメモリを確保
}
return inode; // 新しいinodeを返す
}
inode ビットマップを検索して空き inode を見つけます。空き inode を見つけた場合、ビットマップを更新します。メモリ上に新しい inode 構造体を割り当て、ファイルタイプに基づいて初期化します。dentry と inode の間の参照を設定。リンク数を設定。ファイルタイプが通常のファイルの場合、データブロックを割当。
chiakiFS_sync_inode
メモリ上の inode とその関連データをディスクに書き戻します。
/**
* @brief メモリinodeとその付属構造をディスクへWriteback
*
* @param inode 同期するinode
* @return int 成功時は0を返し、失敗時はエラーコードを返す
*/
int chiakiFS_sync_inode(struct chiakiFS_inode *inode)
{
struct chiakiFS_inode_d inode_d; // ディスクに保存するためのinode構造体
struct chiakiFS_dentry *dentry_cursor; // dentryリストを巡回するカーソル
struct chiakiFS_dentry_d dentry_d; // ディスクに保存するためのdentry構造体
int ino = inode->ino;
inode_d.ino = ino;
inode_d.size = inode->size;
memcpy(inode_d.target_path, inode->target_path, CHIAKIFS_MAX_FILE_NAME); // ファイル名をコピー
inode_d.ftype = inode->dentry->ftype; // ファイルタイプを設定
inode_d.dir_cnt = inode->dir_cnt; // ディレクトリカウントを設定
inode_d.link_cnt = inode->link_cnt;
int offset, offset_END;
for (int i = 0; i < CHIAKIFS_DATA_PER_FILE; i++)
inode_d.dblk[i] = inode->dblk[i]; // ブロック番号を設定
if (chiakiFS_driver_write(CHIAKIFS_INO_OFS(ino), (uint8_t *)&inode_d,
sizeof(struct chiakiFS_inode_d)) != CHIAKIFS_ERROR_NONE)
{
CHIAKIFS_DBG("[%s] io error\n", __func__);
return -CHIAKIFS_ERROR_IO;
}
/* Cycle 1: INODE 書込*/
/* Cycle 2: DATA 書込*/
if (CHIAKIFS_IS_DIR(inode))
{ // ディレクトリの場合
int blk_synced = 0;
dentry_cursor = inode->dentrys; // dentryカーソルを初期化
// SYNC
while (dentry_cursor && blk_synced < CHIAKIFS_DATA_PER_FILE)
{
offset = CHIAKIFS_DATA_OFS(inode->dblk[blk_synced]); // データオフセットを設定
offset_END = CHIAKIFS_DATA_OFS(inode->dblk[blk_synced] + 1); // データオフセットの終了位置を設定
while (dentry_cursor != NULL && offset < offset_END)
{
memcpy(dentry_d.fname, dentry_cursor->fname, CHIAKIFS_MAX_FILE_NAME);
dentry_d.ftype = dentry_cursor->ftype;
dentry_d.ino = dentry_cursor->ino;
if (chiakiFS_driver_write(offset, (uint8_t *)&dentry_d,
sizeof(struct chiakiFS_dentry_d)) != CHIAKIFS_ERROR_NONE)
{
CHIAKIFS_DBG("[%s] io error\n", __func__);
return -CHIAKIFS_ERROR_IO;
}
if (dentry_cursor->inode != NULL)
{
chiakiFS_sync_inode(dentry_cursor->inode); // 子inodeを再帰的に同期
}
dentry_cursor = dentry_cursor->brother; // 次のdentryに進む
offset += sizeof(struct chiakiFS_dentry_d); // オフセットを進める
}
blk_synced++;
}
}
else if (CHIAKIFS_IS_REG(inode))
{ // レギュラーファイルの場合
for (int blk_synced = 0; blk_synced < CHIAKIFS_DATA_PER_FILE; blk_synced++)
{
if (inode->dblk[blk_synced] == 0)
{
break; // これ以上データブロックがない場合、ループを終了
}
if (chiakiFS_driver_write(CHIAKIFS_DATA_OFS(inode->dblk[blk_synced]),
inode->data[blk_synced],
CHIAKIFS_BLK_SZ()) != CHIAKIFS_ERROR_NONE)
{
CHIAKIFS_DBG("[%s] io error\n", __func__);
return -CHIAKIFS_ERROR_IO;
}
}
}
return CHIAKIFS_ERROR_NONE;
}
inode 情報をディスクストレージ用の構造体にコピーします。inode をディスクに書き込みます。inode がディレクトリの場合、dentry リストを走査し、各 dentry をディスクに書き込み。子 inode が存在する場合、chiakiFS_sync_inode
を再帰的に呼び出し。inode が通常のファイルの場合、データブロックをディスクに書き込み。
chiakiFS_drop_inode
メモリ上の inode を削除し、関連するデータブロックとビットマップを更新します。
/**
* @brief メモリのinodeを削除、だがメモリ領域を解放しません
* Case 1: Reg File
*
* Inode
* / \
* Dentry -> Dentry (Reg Dentry)
* |
* Inode (Reg File)
*
* 1) Step 1. Erase Bitmap
* 2) Step 2. Free Inode (Function of chiakiFS_drop_inode)
* ------------------------------------------------------------------------
* 3) *Setp 3. Free Dentry belonging to Inode (Outsider)
* ========================================================================
* Case 2: Dir
* Inode
* / \
* Dentry -> Dentry (Dir Dentry)
* |
* Inode (Dir)
* / \
* Dentry -> Dentry
*
* Recursive
* @param inode
* @return int
*/
int chiakiFS_drop_inode(struct chiakiFS_inode *inode)
{
struct chiakiFS_dentry *dentry_cursor;
struct chiakiFS_dentry *next_dentry;
int ino = inode->ino;
int byte_index, bit_index;
if (inode == chiakiFS_super.root_dentry->inode)
{
return CHIAKIFS_ERROR_INVAL; // ルートinodeは削除できない
}
if (CHIAKIFS_IS_DIR(inode))
{
// 子inodeを再帰的に削除
dentry_cursor = inode->dentrys;
while (dentry_cursor)
{
next_dentry = dentry_cursor->brother; // 次のdentryを保存
chiakiFS_drop_inode(dentry_cursor->inode); // 子inodeを再帰的に削除
chiakiFS_drop_dentry(inode, dentry_cursor); // 親からdentryを削除
free(dentry_cursor); // dentryを解放
dentry_cursor = next_dentry;
}
// ディレクトリが使用しているデータブロックを解放
for (int blk_cursor = 0; blk_cursor < CHIAKIFS_DATA_PER_FILE; blk_cursor++)
{
int dblk = inode->dblk[blk_cursor];
if (dblk == 0)
continue; // データブロックがもうない場合
// ビットマップでデータブロックを空きとする
byte_index = dblk / UINT8_BITS;
bit_index = dblk % UINT8_BITS;
chiakiFS_super.map_data[byte_index] &= (uint8_t)(~(0x1 << bit_index));
inode->dblk[blk_cursor] = 0; // ブロック番号をクリア
}
}
else if (CHIAKIFS_IS_REG(inode) || CHIAKIFS_IS_SYM_LINK(inode))
{
// ファイルが使用しているデータブロックを解放
for (int blk_cursor = 0; blk_cursor < CHIAKIFS_DATA_PER_FILE; blk_cursor++)
{
int dblk = inode->dblk[blk_cursor];
if (dblk == 0)
continue; // データブロックがもうない場合
// ビットマップでデータブロックを空きとする
byte_index = dblk / UINT8_BITS;
bit_index = dblk % UINT8_BITS;
chiakiFS_super.map_data[byte_index] &= (uint8_t)(~(0x1 << bit_index));
inode->dblk[blk_cursor] = 0; // ブロック番号をクリア
if (inode->data[blk_cursor])
{
free(inode->data[blk_cursor]); // データバッファを解放
inode->data[blk_cursor] = NULL;
}
}
}
// inodeビットマップでinodeを空きとする
byte_index = ino / UINT8_BITS;
bit_index = ino % UINT8_BITS;
chiakiFS_super.map_inode[byte_index] &= (uint8_t)(~(0x1 << bit_index));
free(inode);
return CHIAKIFS_ERROR_NONE;
}
ルート inode でないことを確認して、inode がディレクトリである場合、子 inode を再帰的に削除し、関連するデータブロックを解放します。inode が通常のファイルまたはシンボリックリンクの場合、データブロックを解放します。んでinode ビットマップを更新し、inode 構造体を解放。
chiakiFS_read_inode
ディスクから inode を読み取り、メモリ上に inode 構造体を構築します。
/**
* @brief
*
* @param dentry dentry->ino->inode
* @param ino inode
* @return struct chiakiFS_inode* 読み込んだinode構造体を返す
*/
struct chiakiFS_inode *chiakiFS_read_inode(struct chiakiFS_dentry *dentry, int ino)
{
struct chiakiFS_inode *inode = (struct chiakiFS_inode *)malloc(sizeof(struct chiakiFS_inode)); // inode構造体をメモリに確保
struct chiakiFS_inode_d inode_d;
struct chiakiFS_dentry *sub_dentry;
struct chiakiFS_dentry_d dentry_d;
int blk_cnt = 0, dir_cnt = 0, i, offset, offset_END;
if (chiakiFS_driver_read(CHIAKIFS_INO_OFS(ino), (uint8_t *)&inode_d,
sizeof(struct chiakiFS_inode_d)) != CHIAKIFS_ERROR_NONE)
{
CHIAKIFS_DBG("[%s] io error\n", __func__);
return NULL;
}
inode->dir_cnt = 0;
inode->link_cnt = inode_d.link_cnt;
inode->ino = inode_d.ino;
inode->size = inode_d.size;
memcpy(inode->target_path, inode_d.target_path, CHIAKIFS_MAX_FILE_NAME); // パス名をコピー
inode->dentry = dentry;
inode->dentrys = NULL;
for (i = 0; i < CHIAKIFS_DATA_PER_FILE; i++)
inode->dblk[i] = inode_d.dblk[i];
if (CHIAKIFS_IS_DIR(inode))
{
dir_cnt = inode_d.dir_cnt; // ディレクトリカウントを設定
blk_cnt = 0; // 読み込まれたブロック数
while (dir_cnt && blk_cnt < CHIAKIFS_DATA_PER_FILE)
{
offset = CHIAKIFS_DATA_OFS(inode->dblk[blk_cnt]);
offset_END = CHIAKIFS_DATA_OFS(inode->dblk[blk_cnt] + 1);
while (offset < offset_END && dir_cnt > 0)
{
if (chiakiFS_driver_read(offset,
(uint8_t *)&dentry_d,
sizeof(struct chiakiFS_dentry_d)) != CHIAKIFS_ERROR_NONE)
{
CHIAKIFS_DBG("[%s] io error\n", __func__);
return NULL;
}
sub_dentry = new_dentry(dentry_d.fname, dentry_d.ftype); // 新しいdentryを生成
sub_dentry->parent = inode->dentry;
sub_dentry->ino = dentry_d.ino;
sub_dentry->inode = NULL;
chiakiFS_alloc_dentry(inode, sub_dentry, FALSE); // dentryをinodeに割り当て
offset += sizeof(struct chiakiFS_dentry_d);
dir_cnt--;
}
}
}
else if (CHIAKIFS_IS_REG(inode))
{
for (int blk_cnt = 0; blk_cnt < CHIAKIFS_DATA_PER_FILE; blk_cnt++)
{
if (inode->dblk[blk_cnt] == 0)
{
break; // データブロックがもうない場合
}
inode->data[blk_cnt] = (uint8_t *)malloc(CHIAKIFS_BLK_SZ()); // データブロックをメモリに確保
if (chiakiFS_driver_read(CHIAKIFS_DATA_OFS(inode->dblk[blk_cnt]),
inode->data[blk_cnt],
CHIAKIFS_BLK_SZ()) != CHIAKIFS_ERROR_NONE)
{
CHIAKIFS_DBG("[%s] io error\n", __func__);
return NULL;
}
}
}
return inode; // 読み込んだinodeを返す
}
ディスクから inode データを読み取ります。inode 構造体を初期化し、読み取ったデータを設定します。inode がディレクトリであれば、関連する dentry をメモリに読み込みます。inode が通常のファイルであれば、データブロックを読み込みます。
chiakiFS_get_dentry
inode の dentry リストから指定されたインデックスの dentry を取得します。
/**
* @brief inodeのdentrysで欲しいdentryを取得
*
* @param inode inode
* @param dir [0...]
* @return struct chiakiFS_dentry*
*/
struct chiakiFS_dentry *chiakiFS_get_dentry(struct chiakiFS_inode *inode, int dir)
{
struct chiakiFS_dentry *dentry_cursor = inode->dentrys;
int cnt = 0;
while (dentry_cursor)
{
if (dir == cnt)
{
return dentry_cursor;
}
cnt++;
dentry_cursor = dentry_cursor->brother;
}
return NULL;
}
inode の dentry リストを走査し。指定されたインデックスに達したら、その dentry を返します。見つからなければ NULL を返します。
chiakiFS_lookup
指定されたパスを検索し、対応する dentry を取得します。
/**
* @brief
* path: /qwe/ad total_lvl = 2,
* 1) find /'s inode lvl = 1
* 2) find qwe's dentry
* 3) find qwe's inode lvl = 2
* 4) find ad's dentry
*
* path: /qwe total_lvl = 1,
* 1) find /'s inode lvl = 1
* 2) find qwe's dentry
*
* @param path
* @return struct chiakiFS_inode*
*/
struct chiakiFS_dentry *chiakiFS_lookup(const char *path, boolean *is_find, boolean *is_root)
{
struct chiakiFS_dentry *dentry_cursor = chiakiFS_super.root_dentry; // ルートdentryから探索を開始
struct chiakiFS_dentry *dentry_ret = NULL;
struct chiakiFS_inode *inode;
int total_lvl = chiakiFS_calc_lvl(path); // パスの階層数を計算
int lvl = 0;
boolean is_hit;
char *fname = NULL;
char *path_cpy = (char *)malloc(strlen(path) + 1); // パスのコピーを作成
*is_root = FALSE;
strcpy(path_cpy, path);
if (total_lvl == 0)
{ /* ルートディレクトリ */
*is_find = TRUE;
*is_root = TRUE;
dentry_ret = chiakiFS_super.root_dentry;
}
fname = strtok(path_cpy, "/"); // パスを分割してファイル名を取得
while (fname)
{
lvl++;
if (dentry_cursor->inode == NULL)
{ /* Cache仕組み */
chiakiFS_read_inode(dentry_cursor, dentry_cursor->ino); // inodeを読み込む
}
inode = dentry_cursor->inode;
if (CHIAKIFS_IS_REG(inode) && lvl < total_lvl)
{
CHIAKIFS_DBG("[%s] not a dir\n", __func__); // ディレクトリではない場合
dentry_ret = inode->dentry;
break;
}
if (CHIAKIFS_IS_DIR(inode))
{
dentry_cursor = inode->dentrys; // 子dentryに移動
is_hit = FALSE;
while (dentry_cursor)
{
if (strcmp(dentry_cursor->fname, fname) == 0)
{
is_hit = TRUE; // ファイル名が一致する場合
break;
}
dentry_cursor = dentry_cursor->brother; // 次のdentryに進む
}
if (!is_hit)
{
*is_find = FALSE;
CHIAKIFS_DBG("[%s] not found %s\n", __func__, fname); // ファイルが見つからない場合
dentry_ret = inode->dentry;
break;
}
if (is_hit && lvl == total_lvl)
{
*is_find = TRUE;
dentry_ret = dentry_cursor; // 最後のレベルで一致した場合
break;
}
}
fname = strtok(NULL, "/"); // 次の階層のファイル名に進む
}
if (dentry_ret->inode == NULL)
{
dentry_ret->inode = chiakiFS_read_inode(dentry_ret, dentry_ret->ino); // inodeを読み込む
}
return dentry_ret;
}
パスを '/'
で分割し、各レベルのファイル名を取得します。ルートディレクトリから始めて、各レベルで対応する dentry を検索します。dentry を見つけた場合、その inode を読み込むか取得します。最終的に見つかった dentry を返します。
chiakiFS_mount
chiakiFS ファイルシステムをマウントし、必要に応じて初期化を行います。
/**
* @brief chiakiFSをマウントし、以下のようにレイアウトを設定する
*
* Layout
* | Super | Inode Map | Data Block Map | Inode | Data |
*
* IO_SZ = BLK_SZ
*
* 各Inodeは1つのBlkを占有
* @param options マウントオプション
* @return int エラーステータスを返す
*/
int chiakiFS_mount(struct custom_options options)
{
int ret = CHIAKIFS_ERROR_NONE;
int driver_fd;
struct chiakiFS_super_d chiakiFS_super_d;
struct chiakiFS_dentry *root_dentry;
struct chiakiFS_inode *root_inode;
int inode_num;
int map_inode_blks;
int data_num;
int map_data_blks;
int super_blks;
boolean is_init = FALSE;
chiakiFS_super.is_mounted = FALSE;
// driver_fd = open(options.device, O_RDWR);
driver_fd = ddriver_open(options.device); // デバイスを開く
if (driver_fd < 0)
{
return driver_fd;
}
chiakiFS_super.driver_fd = driver_fd;
ddriver_ioctl(CHIAKIFS_DRIVER(), IOC_REQ_DEVICE_SIZE, &chiakiFS_super.sz_disk); // ディスクサイズを取得
ddriver_ioctl(CHIAKIFS_DRIVER(), IOC_REQ_DEVICE_IO_SZ, &chiakiFS_super.sz_io); // IOサイズを取得
chiakiFS_super.sz_blk = 2 * chiakiFS_super.sz_io;
root_dentry = new_dentry("/", CHIAKIFS_DIR); // ルートディレクトリdentryを作成
if (chiakiFS_driver_read(CHIAKIFS_SUPER_OFS, (uint8_t *)(&chiakiFS_super_d),
sizeof(struct chiakiFS_super_d)) != CHIAKIFS_ERROR_NONE)
{
return -CHIAKIFS_ERROR_IO;
}
/* super読込 */
if (chiakiFS_super_d.magic_num != CHIAKIFS_MAGIC)
{ /* マジックナンバーが不一致 */
/* Layout */
super_blks = CHIAKIFS_SUPER_BLKS;
map_inode_blks = CHIAKIFS_MAP_INODE_BLKS;
map_data_blks = CHIAKIFS_MAP_DATA_BLKS;
inode_num = CHIAKIFS_INODE_BLKS * CHIAKIFS_INODE_PER_BLOCK;
data_num = CHIAKIFS_DATA_BLKS;
/* Layout */
chiakiFS_super.max_ino = inode_num;
chiakiFS_super.max_data = data_num;
chiakiFS_super_d.map_inode_offset = CHIAKIFS_SUPER_OFS + CHIAKIFS_BLKS_SZ(super_blks);
chiakiFS_super_d.map_data_offset = chiakiFS_super_d.map_inode_offset + CHIAKIFS_BLKS_SZ(map_inode_blks);
chiakiFS_super_d.inode_offset = chiakiFS_super_d.map_data_offset + CHIAKIFS_BLKS_SZ(map_data_blks);
chiakiFS_super_d.data_offset = chiakiFS_super_d.inode_offset + CHIAKIFS_BLKS_SZ(CHIAKIFS_INODE_BLKS);
chiakiFS_super_d.map_inode_blks = map_inode_blks;
chiakiFS_super_d.map_data_blks = map_data_blks;
chiakiFS_super_d.sz_usage = 0;
CHIAKIFS_DBG("inode map blocks: %d\n", map_inode_blks);
is_init = TRUE;
}
else
{
chiakiFS_super.max_ino = chiakiFS_super_d.max_ino;
chiakiFS_super.max_data = chiakiFS_super_d.max_data;
}
chiakiFS_super.sz_usage = chiakiFS_super_d.sz_usage; /* in-memory 構造 */
chiakiFS_super.map_inode = (uint8_t *)malloc(CHIAKIFS_BLKS_SZ(chiakiFS_super_d.map_inode_blks)); // inodeマップのメモリを確保
chiakiFS_super.map_inode_blks = chiakiFS_super_d.map_inode_blks;
chiakiFS_super.map_inode_offset = chiakiFS_super_d.map_inode_offset;
chiakiFS_super.inode_offset = chiakiFS_super_d.inode_offset;
chiakiFS_super.map_data = (uint8_t *)malloc(CHIAKIFS_BLKS_SZ(chiakiFS_super_d.map_data_blks)); // データマップのメモリを確保
chiakiFS_super.map_data_blks = chiakiFS_super_d.map_data_blks;
chiakiFS_super.map_data_offset = chiakiFS_super_d.map_data_offset;
chiakiFS_super.data_offset = chiakiFS_super_d.data_offset;
if (chiakiFS_driver_read(chiakiFS_super_d.map_inode_offset, (uint8_t *)(chiakiFS_super.map_inode),
CHIAKIFS_BLKS_SZ(chiakiFS_super_d.map_inode_blks)) != CHIAKIFS_ERROR_NONE)
{
return -CHIAKIFS_ERROR_IO;
}
if (chiakiFS_driver_read(chiakiFS_super_d.map_data_offset, (uint8_t *)(chiakiFS_super.map_data),
CHIAKIFS_BLKS_SZ(chiakiFS_super_d.map_data_blks)) != CHIAKIFS_ERROR_NONE)
{
return -CHIAKIFS_ERROR_IO;
}
if (is_init)
{ /* ルートinode割当 */
root_inode = chiakiFS_alloc_inode(root_dentry);
chiakiFS_sync_inode(root_inode); // ルートinodeを同期
}
root_inode = chiakiFS_read_inode(root_dentry, CHIAKIFS_ROOT_INO); // ルートinodeを読み込む
root_dentry->inode = root_inode;
chiakiFS_super.root_dentry = root_dentry;
chiakiFS_super.is_mounted = TRUE;
printf("\n\nThis is Inode Map:\n");
chiakiFS_dump_Imap(); // Iマップをダンプ
printf("\n\nThis is Data Map:\n");
chiakiFS_dump_Dmap(); // Dマップをダンプ
return ret;
}
デバイスを開き、デバイスのサイズと I/O サイズを取得します。スーパー ブロックを読み込み、マジックナンバーを確認します。マジックナンバーが一致しない場合、ファイルシステムを初期化します。ビットマップとオフセットを設定し、メモリにロードします。ルート inode を読み込み、ファイルシステムのルート dentry と inode を設定します。ファイルシステムをマウント状態に設定します。
chiakiFS_umount
ファイルシステムをアンマウントし、メモリ内のデータをディスクに書き戻します。
/**
* @brief chiakiFSをアンマウントし、必要なデータを保存する
*
* @return int エラーステータスを返す
*/
int chiakiFS_umount()
{
struct chiakiFS_super_d chiakiFS_super_d;
if (!chiakiFS_super.is_mounted)
{
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_sync_inode(chiakiFS_super.root_dentry->inode); /* ルーとから全てをsync */
chiakiFS_super_d.magic_num = CHIAKIFS_MAGIC;
chiakiFS_super_d.map_inode_blks = chiakiFS_super.map_inode_blks;
chiakiFS_super_d.map_inode_offset = chiakiFS_super.map_inode_offset;
chiakiFS_super_d.inode_offset = chiakiFS_super.inode_offset;
chiakiFS_super_d.map_data_blks = chiakiFS_super.map_data_blks;
chiakiFS_super_d.map_data_offset = chiakiFS_super.map_data_offset;
chiakiFS_super_d.data_offset = chiakiFS_super.data_offset;
chiakiFS_super_d.sz_usage = chiakiFS_super.sz_usage;
chiakiFS_super_d.max_ino = chiakiFS_super.max_ino;
chiakiFS_super_d.max_data = chiakiFS_super.max_data;
if (chiakiFS_driver_write(CHIAKIFS_SUPER_OFS, (uint8_t *)&chiakiFS_super_d,
sizeof(struct chiakiFS_super_d)) != CHIAKIFS_ERROR_NONE)
{
return -CHIAKIFS_ERROR_IO;
}
if (chiakiFS_driver_write(chiakiFS_super_d.map_inode_offset, (uint8_t *)(chiakiFS_super.map_inode),
CHIAKIFS_BLKS_SZ(chiakiFS_super_d.map_inode_blks)) != CHIAKIFS_ERROR_NONE)
{
return -CHIAKIFS_ERROR_IO;
}
if (chiakiFS_driver_write(chiakiFS_super_d.map_data_offset, (uint8_t *)(chiakiFS_super.map_data),
CHIAKIFS_BLKS_SZ(chiakiFS_super_d.map_data_blks)) != CHIAKIFS_ERROR_NONE)
{
return -CHIAKIFS_ERROR_IO;
}
free(chiakiFS_super.map_inode); // inodeマップを解放
free(chiakiFS_super.map_data); // データマップを解放
ddriver_close(CHIAKIFS_DRIVER()); // デバイスを閉じる
return CHIAKIFS_ERROR_NONE;
}
ファイルシステムがマウントされていることを確認します。ルート inode から始めて、すべての inode を同期します。スーパー ブロックとビットマップをディスクに書き戻します。メモリ内のリソースを解放し、デバイスを閉じます。
FUSEのホック関数デザイン
次は、実現されたFUSEホック:
/******************************************************************************
* SECTION: FUSEの諸オペレーション
*******************************************************************************/
static struct fuse_operations operations = {
.init = chiakiFS_init, /* FSを MOUNT */
.destroy = chiakiFS_destroy, /* FSを UNMOUNT */
.mkdir = chiakiFS_mkdir, /* MKDIR */
.getattr = chiakiFS_getattr, /* STATと似ている、プロパティを取得 */
.readdir = chiakiFS_readdir, /* Dentrys添付*/
.mknod = chiakiFS_mknod, /* TOUCHの必要成分、新規ファイル */
.write = chiakiFS_write, /* ファイル書き込み */
.read = chiakiFS_read, /* ファイル読み込み */
.utimens = chiakiFS_utimens, /* TOUCHのPANICを防ぐため、時間を更新 */
.truncate= chiakiFS_truncate, /* ファイルサイズを変更 */
.unlink = chiakiFS_unlink, /* ファイル削除 */
.rmdir = chiakiFS_rmdir, /* ディレクトリ削除、 rm -r */
.rename = chiakiFS_rename, /* リネーム,mv */
.symlink = chiakiFS_symlink, /* シンボリックリンク, ln -s*/
.link = chiakiFS_link, /* ハードリンク, link*/
.readlink= chiakiFS_readlink, /* シンボリックリンク解析, readlink*/
.open = chiakiFS_open, /* ファイル オープン */
.opendir = chiakiFS_opendir, /* ディレクトリ オープン */
.access = chiakiFS_access /* アクセス ホック */
};
chiakiFS_init
ファイルシステムのマウント時に呼び出されます。
/**
* @brief FSを MOUNT
*
* @param conn_info 接続の確立に関する、無視でいい
* @return void*
*/
void* chiakiFS_init(struct fuse_conn_info * conn_info) {
/* TODO: ここで MOUNT */
if (chiakiFS_mount(chiakiFS_options) != CHIAKIFS_ERROR_NONE) {
CHIAKIFS_DBG("[%s] mount error\n", __func__);
fuse_exit(fuse_get_context()->fuse);
return NULL;
}
return NULL;
/* デバイスの制御例 */
//super.fd = ddriver_open(chiakiFS_options.device);
}
chiakiFS_mount(&chiakiFS_options)
を呼び出してマウント操作を実行します。マウントに失敗した場合、fuse_exit
を呼び出してFUSEを終了します。NULL
を返すことで初期化が完了したことを示します。
chiakiFS_destroy
ファイルシステムのアンマウント時に呼び出されます。
/**
* @brief FSを UNMOUNT
*
* @param p 無視でいい
* @return void
*/
void chiakiFS_destroy(void* p) {
/* TODO: ここで UNMOUNT */
if (chiakiFS_umount() != CHIAKIFS_ERROR_NONE) {
CHIAKIFS_DBG("[%s] unmount error\n", __func__);
fuse_exit(fuse_get_context()->fuse);
return;
}
//ddriver_close(super.fd);
return;
}
chiakiFS_umount()
を呼び出してアンマウント操作を実行します。アンマウントに失敗した場合、fuse_exit
を呼び出してFUSEを終了します。
chiakiFS_mkdir
ディレクトリを作成します。
/**
* @brief MKDIR
*
* @param path マウントポイントを基準とした相対パス
* @param mode モード(READONLY? WRITEONLY?),無視でいい
* @return int 成功なら0(CHIAKIFS_ERROR_NONE),否と、対応するエラーコード
*/
int chiakiFS_mkdir(const char* path, mode_t mode) {
/* TODO: パスを解析,新規ディレクトリを作る */
(void)mode; // モードは使用しない
boolean is_find, is_root; // ディレクトリの検索結果を保存
char* fname; // 新しいディレクトリの名前
struct chiakiFS_dentry* last_dentry = chiakiFS_lookup(path, &is_find, &is_root); // パスに基づいてディレクトリエントリを検索
struct chiakiFS_dentry* dentry; // 新規ディレクトリエントリ
struct chiakiFS_inode* inode; // 新規ディレクトリのinode
if (is_find) { // すでに存在する場合
return -CHIAKIFS_ERROR_EXISTS;
}
if (CHIAKIFS_IS_REG(last_dentry->inode)) { // 最後のエントリがファイルの場合はエラー
return -CHIAKIFS_ERROR_UNSUPPORTED;
}
fname = chiakiFS_get_fname(path); // 新しいディレクトリ名を取得
dentry = new_dentry(fname, CHIAKIFS_DIR); // 新しいディレクトリエントリを作成
dentry->parent = last_dentry; // 親ディレクトリを設定
inode = chiakiFS_alloc_inode(dentry); // 新しいinodeを割り当て
inode -> link_cnt = 2; //ディレクトリのリンク数は2
chiakiFS_alloc_dentry(last_dentry->inode, dentry, TRUE); // 親ディレクトリに新しいエントリを追加
last_dentry->inode->link_cnt++;
chiakiFS_sync_inode(last_dentry->inode);
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。ディレクトリが既に存在する場合、エラーを返します。親ディレクトリのdentryを取得します。新しいdentryとinodeを作成し、それを親ディレクトリに追加します。
chiakiFS_getattr
ファイルまたはディレクトリの属性を取得します。
/**
* @brief ファイルまたはディレクトリの属性を取得する、非常に重要!!!
*
* @param path マウントポイントに対するパス
* @param chiakiFS_stat ステータスの返り
* @return int 成功なら0、否と、対応するエラーコード
*/
int chiakiFS_getattr(const char* path, struct stat * chiakiFS_stat) {
/* TODO: パスを解析してInodeを取得し、chiakiFS_statを設定する。/fs/simplefs/sfs.cのsfs_getattr()関数の実装を参考にできる */
boolean is_find, is_root; // ディレクトリの検索結果を保存
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root); // パスに基づいてディレクトリエントリを検索
if (is_find == FALSE) { // エントリが見つからない場合
return -CHIAKIFS_ERROR_NOTFOUND;
}
if (CHIAKIFS_IS_DIR(dentry->inode)) { // ディレクトリの場合
chiakiFS_stat->st_mode = S_IFDIR | CHIAKIFS_DEFAULT_PERM;
chiakiFS_stat->st_size = dentry->inode->dir_cnt * sizeof(struct chiakiFS_dentry_d); // ディレクトリサイズを設定
}
else if (CHIAKIFS_IS_REG(dentry->inode)) { // 通常ファイルの場合
chiakiFS_stat->st_mode = S_IFREG | CHIAKIFS_DEFAULT_PERM;
chiakiFS_stat->st_size = dentry->inode->size; // ファイルサイズを設定
}
else if (CHIAKIFS_IS_SYM_LINK(dentry->inode)) { // シンボリックリンクの場合
chiakiFS_stat->st_mode = S_IFLNK | CHIAKIFS_DEFAULT_PERM;
chiakiFS_stat->st_size = dentry->inode->size; // リンクサイズを設定
}
chiakiFS_stat->st_uid = getuid(); // ユーザーID
chiakiFS_stat->st_gid = getgid(); // グループID
chiakiFS_stat->st_atime = time(NULL); // アクセス時間
chiakiFS_stat->st_mtime = time(NULL); // 更新時間
chiakiFS_stat->st_blksize = CHIAKIFS_BLK_SZ(); // 論理ブロックサイズ
chiakiFS_stat->st_ino = dentry->inode->ino; // Inode番号
chiakiFS_stat->st_nlink = dentry->inode->link_cnt; // リンク数
if (is_root) { // ルートディレクトリの場合
chiakiFS_stat->st_size = chiakiFS_super.sz_usage;
chiakiFS_stat->st_blocks = CHIAKIFS_DISK_SZ() / CHIAKIFS_BLK_SZ(); // 総ブロック数
chiakiFS_stat->st_nlink = 2; // ルートディレクトリのリンク数は2
}
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。dentryの種類に基づいてstat構造体の各フィールドを設定します。
chiakiFS_readdir
ディレクトリの内容を読み取ります。
/**
* @brief ディレクトリエントリを走査し、バッファに挿入し、FUSEに渡す
*
* @param path マウントポイントに対するパス
* @param buf 出力バッファ
* @param filler パラメータの説明:
*
* typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
* const struct stat *stbuf, off_t off)
* buf: nameがbufにコピーされる
* name: dentryの名前
* stbuf: ファイルのステータス、無視できる
* off: 次のオフセット、ここは何番目のdentryかを理解でいい
*
* @param offset 何番目のディレクトリエントリ
* @param fi 無視できる
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_readdir(const char * path, void * buf, fuse_fill_dir_t filler, off_t offset,
struct fuse_file_info * fi) {
/* TODO: /fs/simplefs/sfs.cのsfs_readdir()関数の実装を参考にできる */
boolean is_find, is_root; // ディレクトリの検索結果を保存
int cur_dir = offset; // 現在のディレクトリエントリの位置
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root); // パスに基づいてディレクトリエントリを検索
struct chiakiFS_dentry* sub_dentry; // サブディレクトリエントリ
struct chiakiFS_inode* inode; // ディレクトリのinode
if (is_find) { // ディレクトリが見つかった場合
inode = dentry->inode;
sub_dentry = chiakiFS_get_dentry(inode, cur_dir); // 現在のディレクトリ位置からサブディレクトリを取得
if (sub_dentry) {
filler(buf, sub_dentry->fname, NULL, ++offset); // バッファにサブディレクトリ名を挿入
}
return CHIAKIFS_ERROR_NONE;
}
return -CHIAKIFS_ERROR_NOTFOUND;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。ディレクトリ内のdentryを巡回し、filler関数を使ってユーザーバッファに内容を埋め込みます。
chiakiFS_mknod
ファイルノード(ファイルまたはディレクトリ)を作成します。
/**
* @brief 新規ファイル作成
*
* @param path マウントポイントに対するパス
* @param mode モード(READONLY? WRITEONLY?),無視でいい
* @param dev デバイスタイプ、無視でいい
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_mknod(const char* path, mode_t mode, dev_t dev) {
/* TODO: パスを解析、ファイルを作成 */
boolean is_find, is_root; // ディレクトリの検索結果を保存
struct chiakiFS_dentry* last_dentry = chiakiFS_lookup(path, &is_find, &is_root); // パスに基づいてディレクトリエントリを検索
struct chiakiFS_dentry* dentry; // 新規ファイルのディレクトリエントリ
struct chiakiFS_inode* inode; // 新規ファイルのinode
char* fname; // ファイル名
if (is_find == TRUE) { // すでに存在する場合
return -CHIAKIFS_ERROR_EXISTS;
}
fname = chiakiFS_get_fname(path); // ファイル名を取得
if (S_ISREG(mode)) { // 通常ファイルの場合
dentry = new_dentry(fname, CHIAKIFS_REG_FILE);
}
else if (S_ISDIR(mode)) { // ディレクトリの場合
dentry = new_dentry(fname, CHIAKIFS_DIR);
}
else { // その他の場合
dentry = new_dentry(fname, CHIAKIFS_REG_FILE);
}
dentry->parent = last_dentry; // 親ディレクトリを設定
inode = chiakiFS_alloc_inode(dentry); // 新しいinodeを割り当て
inode -> link_cnt = 1;
chiakiFS_alloc_dentry(last_dentry->inode, dentry, TRUE); // 親ディレクトリに新しいエントリを追加
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。既に存在する場合、エラーを返します。モードに基づいて新しいdentryとinodeを作成し、それを親ディレクトリに追加します。
chiakiFS_utimens
/**
* @brief TOUCHのPANICを防ぐため、時間を更新
*
* @param path マウントポイントに対するパス
* @param tv 時間
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_utimens(const char* path, const struct timespec tv[2]) {
(void)path;
return 0;
}
chiakiFS_write
ファイルの内容を書き込みます。
/**
* @brief ファイル書き込み
*
* @param path マウントポイントに対するパス
* @param buf 書き込む内容
* @param size 書き込むサイズ(Byte)
* @param offset ファイル対する書き込みオフセット
* @param fi 無視でいい
* @return int 書き込まれたサイズ
*/
int chiakiFS_write(const char* path, const char* buf, size_t size, off_t offset,
struct fuse_file_info* fi) {
boolean is_find, is_root;
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root); // ファイルのエントリを取得
struct chiakiFS_inode* inode;
int bytes_written = 0;
if (!is_find) {
return -CHIAKIFS_ERROR_NOTFOUND; // ファイルが見つからない場合のエラーハンドリング
}
if (CHIAKIFS_IS_DIR(dentry->inode)) {
return -CHIAKIFS_ERROR_ISDIR; // ディレクトリへの書き込みはエラー
}
inode = dentry->inode;
if (inode == NULL) {
inode = chiakiFS_read_inode(dentry, dentry->ino); // inodeが存在しない場合は読み込む
if (inode == NULL) {
return -CHIAKIFS_ERROR_IO; // 読み込み失敗時のエラーハンドリング
}
dentry->inode = inode;
}
// inodeにデータブロックを割り当てる必要があるか確認
size_t end_offset = offset + size;
size_t required_blocks = CHIAKIFS_ROUND_UP(end_offset, CHIAKIFS_BLK_SZ()) / CHIAKIFS_BLK_SZ();
if (required_blocks > CHIAKIFS_DATA_PER_FILE) {
return -CHIAKIFS_ERROR_NOSPACE; // データブロックが足りない場合のエラーハンドリング
}
// 必要に応じてデータブロックを割り当てる
for (int blk_idx = 0; blk_idx < required_blocks; blk_idx++) {
if (inode->dblk[blk_idx] == 0) {
// 新しいデータブロックを割り当てる必要がある場合
int byte_cursor = 0;
int bit_cursor = 0;
int dno_cursor = 0;
boolean is_find_free_blk = FALSE;
for (byte_cursor = 0; byte_cursor < CHIAKIFS_BLKS_SZ(chiakiFS_super.map_data_blks); byte_cursor++) {
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
if ((chiakiFS_super.map_data[byte_cursor] & (0x1 << bit_cursor)) == 0) {
// 空きデータブロックを見つけた場合
chiakiFS_super.map_data[byte_cursor] |= (0x1 << bit_cursor);
inode->dblk[blk_idx] = dno_cursor;
is_find_free_blk = TRUE;
break;
}
dno_cursor++;
}
if (is_find_free_blk) {
break;
}
}
if (!is_find_free_blk || dno_cursor >= chiakiFS_super.max_data) {
return -CHIAKIFS_ERROR_NOSPACE; // 空きブロックが見つからない場合のエラーハンドリング
}
// データブロックのメモリを確保
inode->data[blk_idx] = (uint8_t*)malloc(CHIAKIFS_BLK_SZ());
memset(inode->data[blk_idx], 0, CHIAKIFS_BLK_SZ()); // 初期化
}
}
// inodeのデータブロックにデータを書き込む
size_t bytes_to_write = size;
size_t buf_offset = 0;
size_t file_offset = offset;
while (bytes_to_write > 0) {
int blk_idx = file_offset / CHIAKIFS_BLK_SZ();
int blk_offset = file_offset % CHIAKIFS_BLK_SZ();
size_t bytes_in_blk = CHIAKIFS_BLK_SZ() - blk_offset;
size_t bytes_this_round = (bytes_to_write < bytes_in_blk) ? bytes_to_write : bytes_in_blk;
memcpy(inode->data[blk_idx] + blk_offset, buf + buf_offset, bytes_this_round); // データコピー
bytes_written += bytes_this_round;
bytes_to_write -= bytes_this_round;
buf_offset += bytes_this_round;
file_offset += bytes_this_round;
}
// 必要に応じてinodeのサイズを更新
if (file_offset > inode->size) {
inode->size = file_offset;
}
// inodeをマークしてディスクに同期
if (chiakiFS_sync_inode(inode) != CHIAKIFS_ERROR_NONE) {
return -CHIAKIFS_ERROR_IO; // 同期エラーの処理
}
return bytes_written; // 書き込まれたバイト数を返す
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返し。
ディレクトリかどうかを確認し、ディレクトリであればエラーを返し。読み取り失敗時もエラーを返し。
必要に応じてデータブロックを割り当て、データを書き込み。ファイルサイズを更新します。chiakiFS_sync_inode(inode)
を呼び出してinodeをディスクに同期します。
chiakiFS_read
ファイルの内容を読み取ります。
/**
* @brief ファイル読込
*
* @param path マウントポイントに対するパス
* @param buf 読込内容
* @param size 読込サイズ
* @param offset ファイル対する読込オフセット
* @param fi 無視でいい
* @return int 読込まれたサイズ
*/
int chiakiFS_read(const char* path, char* buf, size_t size, off_t offset,
struct fuse_file_info* fi) {
boolean is_find, is_root;
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root); // ファイルのエントリを取得
struct chiakiFS_inode* inode;
int bytes_read = 0;
if (!is_find) {
return -CHIAKIFS_ERROR_NOTFOUND; // ファイルが見つからない場合のエラーハンドリング
}
if (CHIAKIFS_IS_DIR(dentry->inode)) {
return -CHIAKIFS_ERROR_ISDIR; // ディレクトリへの読み込みはエラー
}
inode = dentry->inode;
if (inode == NULL) {
inode = chiakiFS_read_inode(dentry, dentry->ino); // inodeが存在しない場合は読み込む
if (inode == NULL) {
return -CHIAKIFS_ERROR_IO; // 読み込み失敗時のエラーハンドリング
}
dentry->inode = inode;
}
if (offset >= inode->size) {
// オフセットがサイズ上限を超えている場合は0を返す
return 0;
}
size_t bytes_to_read = (offset + size > inode->size) ? (inode->size - offset) : size; // 読み込むバイト数を決定
size_t buf_offset = 0;
size_t file_offset = offset;
while (bytes_to_read > 0) {
int blk_idx = file_offset / CHIAKIFS_BLK_SZ();
int blk_offset = file_offset % CHIAKIFS_BLK_SZ();
size_t bytes_in_blk = CHIAKIFS_BLK_SZ() - blk_offset;
size_t bytes_this_round = (bytes_to_read < bytes_in_blk) ? bytes_to_read : bytes_in_blk;
if (inode->data[blk_idx] == NULL) {
// データブロックをディスクからロード
inode->data[blk_idx] = (uint8_t*)malloc(CHIAKIFS_BLK_SZ());
if (chiakiFS_driver_read(CHIAKIFS_DATA_OFS(inode->dblk[blk_idx]),
inode->data[blk_idx],
CHIAKIFS_BLK_SZ()) != CHIAKIFS_ERROR_NONE) {
return -CHIAKIFS_ERROR_IO; // 読み込みエラーの処理
}
}
memcpy(buf + buf_offset, inode->data[blk_idx] + blk_offset, bytes_this_round); // データコピー
bytes_read += bytes_this_round;
bytes_to_read -= bytes_this_round;
buf_offset += bytes_this_round;
file_offset += bytes_this_round;
}
return bytes_read; // 読み込まれたバイト数を返す
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。
ディレクトリかどうかを確認し、ディレクトリであればエラーを返し。読み取り失敗時もエラーを返し。
データブロックからデータを読み取りバイト数、ユーザーに返します。chiakiFS_driver_read
を呼び出してデータブロックの内容を読み取ります。
chiakiFS_unlink
ファイルを削除します。
/**
* @brief ファイル削除
*
* @param path マウントポイントに対するパス
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_unlink(const char* path) {
boolean is_find, is_root;
// 指定されたパスのディレクトリエントリを検索
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root);
struct chiakiFS_dentry* parent_dentry;
struct chiakiFS_inode* parent_inode;
// ファイルが見つからなければエラーを返す
if (!is_find) {
return -CHIAKIFS_ERROR_NOTFOUND;
}
// ディレクトリの場合は削除不可エラーを返す
if (CHIAKIFS_IS_DIR(dentry->inode)) {
return -CHIAKIFS_ERROR_ISDIR;
}
parent_dentry = dentry->parent;
parent_inode = parent_dentry->inode;
// 親ディレクトリのディレクトリエントリリストからエントリを削除
if (chiakiFS_drop_dentry(parent_inode, dentry) < 0) {
return -CHIAKIFS_ERROR_IO;
}
// inodeのリンク数をデクリメント
dentry->inode->link_cnt--;
if (dentry->inode->link_cnt == 0) {
// リンク数が0になったらinodeを解放
if (chiakiFS_drop_inode(dentry->inode) != CHIAKIFS_ERROR_NONE) {
return -CHIAKIFS_ERROR_IO;
}
} else {
// そうでなければinodeを同期
if (chiakiFS_sync_inode(dentry->inode) != CHIAKIFS_ERROR_NONE) {
return -CHIAKIFS_ERROR_IO;
}
}
free(dentry); // dentryのメモリを解放
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。
ディレクトリかどうかを確認し、ディレクトリであればエラーを返し。
親ディレクトリからdentryを削除します。関連するinodeとデータブロックを解放します。chiakiFS_sync_inode(parent_inode)
を呼び出して親inodeをディスクに同期します。
chiakiFS_rmdir
ディレクトリを削除します。
/**
* @brief ディレクトリ削除
*
* ディレクトリ削除は次の通りでいい:
* rm ./tests/mnt/j/ -r
* 1) Step 1. rm ./tests/mnt/j/j
* 2) Step 2. rm ./tests/mnt/j
* まずは中のものを削除、そんでこのディレクトリを削除
*
* @param path マウントポイントに対するパス
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_rmdir(const char* path) {
boolean is_find, is_root;
// 指定されたパスのディレクトリエントリを検索
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root);
struct chiakiFS_dentry* parent_dentry;
struct chiakiFS_inode* parent_inode;
// ディレクトリが見つからなければエラーを返す
if (!is_find) {
return -CHIAKIFS_ERROR_NOTFOUND;
}
// ファイルの場合はディレクトリ削除不可エラーを返す
if (!CHIAKIFS_IS_DIR(dentry->inode)) {
return -CHIAKIFS_ERROR_NOTDIR;
}
// ディレクトリが空でない場合は削除不可エラーを返す
if (dentry->inode->dir_cnt > 0) {
return -ENOTEMPTY;
}
parent_dentry = dentry->parent;
parent_inode = parent_dentry->inode;
// 親ディレクトリのディレクトリエントリリストからエントリを削除
if (chiakiFS_drop_dentry(parent_inode, dentry) < 0) {
return -CHIAKIFS_ERROR_IO;
}
// inodeと関連データブロックの解放
if (chiakiFS_drop_inode(dentry->inode) != CHIAKIFS_ERROR_NONE) {
return -CHIAKIFS_ERROR_IO;
}
// 親inodeをディスクに同期
if (chiakiFS_sync_inode(parent_inode) != CHIAKIFS_ERROR_NONE) {
return -CHIAKIFS_ERROR_IO;
}
parent_inode->link_cnt--;
chiakiFS_sync_inode(parent_inode);
free(dentry); // dentryのメモリを解放
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。
ディレクトリでない場合、エラーを返します。ディレクトリが空でない場合、エラーを返します。
親ディレクトリからdentryを削除します。関連するinodeとデータブロックを解放します。chiakiFS_sync_inode(parent_inode)
を呼び出して親inodeをディスクに同期します。
chiakiFS_rename
ファイルまたはディレクトリの名前を変更します。
/**
* @brief リネーム
*
* @param from ソースパス
* @param to デスティネーションパス
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_rename(const char* from, const char* to) {
boolean is_find_from, is_root_from;
boolean is_find_to, is_root_to;
// ソースパスのディレクトリエントリを検索
struct chiakiFS_dentry* dentry_from = chiakiFS_lookup(from, &is_find_from, &is_root_from);
struct chiakiFS_dentry* dentry_to_parent;
struct chiakiFS_inode* parent_inode_from;
struct chiakiFS_inode* parent_inode_to;
char* to_name;
// ソースが存在しない場合エラーを返す
if (!is_find_from) {
return -CHIAKIFS_ERROR_NOTFOUND;
}
// ターゲットパスがすでに存在する場合エラーを返す
chiakiFS_lookup(to, &is_find_to, &is_root_to);
if (is_find_to) {
return -CHIAKIFS_ERROR_EXISTS;
}
// デスティネーションの親inodeを取得
char* to_parent_path = strdup(to);
to_name = strrchr(to_parent_path, '/');
if (to_name == NULL) {
dentry_to_parent = chiakiFS_super.root_dentry;
to_name = to_parent_path;
} else {
*to_name = '\0';
to_name++;
// ルートディレクトリの場合
if (strlen(to_parent_path) == 0) {
dentry_to_parent = chiakiFS_super.root_dentry;
} else {
// 親ディレクトリを検索し、ディレクトリでない場合はエラーを返す
dentry_to_parent = chiakiFS_lookup(to_parent_path, &is_find_to, &is_root_to);
if (!is_find_to || !CHIAKIFS_IS_DIR(dentry_to_parent->inode)) {
free(to_parent_path);
return -CHIAKIFS_ERROR_NOTDIR;
}
}
}
parent_inode_from = dentry_from->parent->inode;
parent_inode_to = dentry_to_parent->inode;
// 古い親のdentryリストからエントリを削除
if (chiakiFS_drop_dentry(parent_inode_from, dentry_from) < 0) {
free(to_parent_path);
return -CHIAKIFS_ERROR_IO;
}
// dentryの名前と親ディレクトリを更新
memset(dentry_from->fname, 0, CHIAKIFS_MAX_FILE_NAME);
strncpy(dentry_from->fname, to_name, CHIAKIFS_MAX_FILE_NAME - 1);
dentry_from->parent = dentry_to_parent;
// 新しい親のdentryリストにエントリを追加
if (chiakiFS_alloc_dentry(parent_inode_to, dentry_from, TRUE) < 0) {
free(to_parent_path);
return -CHIAKIFS_ERROR_IO;
}
// 両方の親inodeをディスクに同期
if (chiakiFS_sync_inode(parent_inode_from) != CHIAKIFS_ERROR_NONE) {
free(to_parent_path);
return -CHIAKIFS_ERROR_IO;
}
if (chiakiFS_sync_inode(parent_inode_to) != CHIAKIFS_ERROR_NONE) {
free(to_parent_path);
return -CHIAKIFS_ERROR_IO;
}
free(to_parent_path);
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(from, &is_find_from, &is_root_from)
を呼び出して元のパスを検索します。chiakiFS_lookup(to, &is_find_to, &is_root_to)
を呼び出してターゲットパスを検索します。
ターゲットパスが既に存在する場合、エラーを返します。
ターゲットパスの親ディレクトリを取得します。元の親ディレクトリから元のdentryを削除します。
元のdentryの名前と親ディレクトリを更新します、ターゲット親ディレクトリに追加します。chiakiFS_sync_inode(parent_inode_from)
と chiakiFS_sync_inode(parent_inode_to)
を呼び出してinodeをディスクに同期します。
chiakiFS_open
ファイルを開きます。
/**
* @brief ファイルを開く
* 特に、fi->fh は 64 ビット ポインター、保存したいデータ構造を fh に保存できます。
*
* @param path マウントポイントに対するパス
* @param fi ファイルインフォメーション
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_open(const char* path, struct fuse_file_info* fi) {
boolean is_find, is_root;
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root);
if (!is_find) {
return -CHIAKIFS_ERROR_NOTFOUND;
}
if (CHIAKIFS_IS_DIR(dentry->inode)) {
return -CHIAKIFS_ERROR_ISDIR;
}
// ファイルハンドルにinodeポインターを保存
fi->fh = (uint64_t)(uintptr_t)dentry->inode;
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。
ディレクトリかどうかを確認し、ディレクトリであればエラーを返します。inodeポインタを fi->fh
に保存します。
chiakiFS_opendir
ディレクトリを開きます。
/**
* @brief ディレクトリを開く
*
* @param path マウントポイントに対するパス
* @param fi ファイルインフォメーション
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_opendir(const char* path, struct fuse_file_info* fi) {
boolean is_find, is_root;
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root);
if (!is_find) {
return -CHIAKIFS_ERROR_NOTFOUND;
}
if (!CHIAKIFS_IS_DIR(dentry->inode)) {
return -CHIAKIFS_ERROR_NOTDIR;
}
// ファイルハンドルにinodeポインターを保存
fi->fh = (uint64_t)(uintptr_t)dentry->inode;
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。
ディレクトリかどうかを確認し、ディレクトリであればエラーを返します。inodeポインタを fi->fh
に保存します。
chiakiFS_truncate
ファイルのサイズを変更します。
/**
* @brief ファイルサイズを変更
*
* @param path マウントポイントに対するパス
* @param offset 変更後のファイルサイズ
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_truncate(const char* path, off_t offset) {
boolean is_find, is_root;
// 指定されたパスのdentryを検索し、見つかればis_findがtrueになる
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root);
struct chiakiFS_inode* inode;
// dentryが見つからない場合、エラーメッセージを返す
if (!is_find) {
return -CHIAKIFS_ERROR_NOTFOUND;
}
// 指定されたパスがディレクトリの場合、エラーメッセージを返す
if (CHIAKIFS_IS_DIR(dentry->inode)) {
return -CHIAKIFS_ERROR_ISDIR;
}
// inodeがNULLなら、dentryのinodeを読み込み、失敗したらエラーメッセージを返す
inode = dentry->inode;
if (inode == NULL) {
inode = chiakiFS_read_inode(dentry, dentry->ino);
if (inode == NULL) {
return -CHIAKIFS_ERROR_IO;
}
dentry->inode = inode;
}
// ファイルサイズが増える場合、ギャップを0で埋める
if (offset > inode->size) {
size_t additional_size = offset - inode->size;
char* zero_buf = (char*)calloc(additional_size, 1);
// 新しいサイズまで0埋めデータを書き込む
chiakiFS_write(path, zero_buf, additional_size, inode->size, NULL);
free(zero_buf);
} else if (offset < inode->size) {
// ファイルサイズが減る場合、データブロックを切り詰める
size_t required_blocks = CHIAKIFS_ROUND_UP(offset, CHIAKIFS_BLK_SZ()) / CHIAKIFS_BLK_SZ();
// 必要なブロック数より多いブロックを解放する
for (int blk_idx = required_blocks; blk_idx < CHIAKIFS_DATA_PER_FILE; blk_idx++) {
if (inode->dblk[blk_idx] != 0) {
// データブロックの解放処理
int dblk = inode->dblk[blk_idx];
int byte_index = dblk / UINT8_BITS;
int bit_index = dblk % UINT8_BITS;
// データブロックのビットマップを更新し、ブロックを解放
chiakiFS_super.map_data[byte_index] &= (uint8_t)(~(0x1 << bit_index));
inode->dblk[blk_idx] = 0;
if (inode->data[blk_idx]) {
free(inode->data[blk_idx]);
inode->data[blk_idx] = NULL;
}
}
}
// 最後のブロックのデータを調整して0で埋める
if (required_blocks > 0) {
int blk_idx = required_blocks - 1;
int blk_offset = offset % CHIAKIFS_BLK_SZ();
if (inode->data[blk_idx]) {
memset(inode->data[blk_idx] + blk_offset, 0, CHIAKIFS_BLK_SZ() - blk_offset);
}
}
inode->size = offset;
}
// inodeをディスクに同期
if (chiakiFS_sync_inode(inode) != CHIAKIFS_ERROR_NONE) {
return -CHIAKIFS_ERROR_IO;
}
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。見つからない場合、エラーを返します。
ディレクトリかどうかを確認し、ディレクトリであればエラーを返します。
新しいサイズが現在のサイズより大きい場合、新しいデータブロックを割り当ててゼロで埋めます。
新しいサイズが現在のサイズより小さい場合、余分なデータブロックを解放します。ファイルサイズを更新します。chiakiFS_sync_inode(inode)
を呼び出してinodeをディスクに同期します。
chiakiFS_access
ファイルのアクセス権を確認します。
/**
* @brief ファイルをアクセス、権限照合必要
*
* @param path マウントポイントに対するパス
* @param type アクセスタイプ
* R_OK: 読込権限をチェック
* W_OK: 書込権限をチェック
* X_OK: 実行権限をチェック.
* F_OK: 存在性をチェック.
*
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_access(const char* path, int type) {
boolean is_find, is_root;
boolean is_access_ok = FALSE;
chiakiFS_lookup(path, &is_find, &is_root);
switch (type)
{
case R_OK:
is_access_ok = TRUE;
break;
case F_OK:
if (is_find) {
is_access_ok = TRUE;
}
break;
case W_OK:
is_access_ok = TRUE;
break;
case X_OK:
is_access_ok = TRUE;
break;
default:
break;
}
return is_access_ok ? CHIAKIFS_ERROR_NONE : -CHIAKIFS_ERROR_ACCESS;
}
アクセスの種類(R_OK, W_OK, X_OK, F_OK)に基づいて、対応する結果を返します。
chiakiFS_symlink
シンボリックリンクを作成します。
/**
* @brief シンボリックリンクを作る
*
* @param from ソースパス
* @param to シンボリックのパス
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_symlink(const char *from, const char *to) {
boolean is_find, is_root;
char *fname;
struct chiakiFS_dentry *parent_dentry, *sym_dentry;
struct chiakiFS_inode *parent_inode, *inode;
int ret;
// to、既に存在?
chiakiFS_lookup(to, &is_find, &is_root);
if (is_find) {
return -EEXIST;
}
// toの親ディレクトリ
char *parent_path = strdup(to);
char *last_slash = strrchr(parent_path, '/');
if (last_slash == NULL) {
free(parent_path);
return -EINVAL;
}
if (last_slash == parent_path) {
// 親がルート
*(last_slash + 1) = '\0';
} else {
*last_slash = '\0';
}
parent_dentry = chiakiFS_lookup(parent_path, &is_find, &is_root);
free(parent_path);
if (!is_find || !CHIAKIFS_IS_DIR(parent_dentry->inode)) {
return -ENOENT;
}
parent_inode = parent_dentry->inode;
// toのファイルネーム
fname = chiakiFS_get_fname(to);
// New Dentry
sym_dentry = new_dentry(fname, CHIAKIFS_SYM_LINK);
sym_dentry->parent = parent_dentry;
// New inode
inode = chiakiFS_alloc_inode(sym_dentry);
// このinodeのtarget_pathをfromに設置
strncpy(inode->target_path, from, CHIAKIFS_MAX_FILE_NAME - 1);
inode->target_path[CHIAKIFS_MAX_FILE_NAME - 1] = '\0';
// ファイルサイズをリンク元のサイズに設置
inode->size = strlen(from);
// dentryをparentへ接続
chiakiFS_alloc_dentry(parent_inode, sym_dentry, TRUE);
// ディスクへ保存
ret = chiakiFS_sync_inode(inode);
if (ret != CHIAKIFS_ERROR_NONE) {
return ret;
}
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(to, &is_find_to, &is_root_to)
を呼び出してターゲットパスを検索します。既に存在する場合、エラーを返します。
ターゲットパスの親ディレクトリを取得します。新しいdentryとinodeを作成し、シンボリックリンクのターゲットパスを設定します。
新しいdentryを親ディレクトリに追加します。chiakiFS_sync_inode(inode)
を呼び出してinodeをディスクに同期します。
chiakiFS_readlink
シンボリックリンクのターゲットパスを読み取ります。
/**
* @brief シンボリックリンクを解析
*
* @param path シンボリックパス
* @param buf 解析されたパスをここに
* @param size bufの最大長('\0'を含め)
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_readlink(const char *path, char *buf, size_t size) {
boolean is_find, is_root;
struct chiakiFS_dentry* dentry = chiakiFS_lookup(path, &is_find, &is_root);
if (!is_find) {
return -ENOENT;
}
//シンボリックリンクではない
if (!CHIAKIFS_IS_SYM_LINK(dentry->inode)) {
return -EINVAL;
}
size_t len = strlen(dentry->inode->target_path);
if (len >= size) {
len = size - 1;
}
memcpy(buf, dentry->inode->target_path, len);
buf[len] = '\0';
return 0;
}
chiakiFS_lookup(path, &is_find, &is_root)
を呼び出してパスを検索します。シンボリックリンクでない場合、エラーを返します。シンボリックリンクのターゲットパスをユーザーバッファにコピーします。
chiakiFS_link
ハードリンクを作成します。
/**
* @brief ハードリンクを作る
*
* @param from ソースパス
* @param to リンクのパス
* @return int 成功なら0、失敗時は対応するエラーコード
*/
int chiakiFS_link(const char *from, const char *to) {
boolean is_find_from, is_root_from;
boolean is_find_to, is_root_to;
struct chiakiFS_dentry *from_dentry, *parent_dentry, *link_dentry;
struct chiakiFS_inode *parent_inode;
char *fname;
// from存在か?
from_dentry = chiakiFS_lookup(from, &is_find_from, &is_root_from);
if (!is_find_from) {
return -ENOENT;
}
// ディレクトリへのハードリンクは不可
if (CHIAKIFS_IS_DIR(from_dentry->inode)) {
return -EPERM;
}
// to存在か?
chiakiFS_lookup(to, &is_find_to, &is_root_to);
if (is_find_to) {
return -EEXIST;
}
// toの親ディレクトリ
char *parent_path = strdup(to);
char *last_slash = strrchr(parent_path, '/');
if (last_slash == NULL) {
free(parent_path);
return -EINVAL;
}
if (last_slash == parent_path) {
// 親がルート
*(last_slash + 1) = '\0';
} else {
*last_slash = '\0';
}
parent_dentry = chiakiFS_lookup(parent_path, &is_find_to, &is_root_to);
free(parent_path);
if (!is_find_to || !CHIAKIFS_IS_DIR(parent_dentry->inode)) {
return -ENOENT;
}
parent_inode = parent_dentry->inode;
// toのファイルネーム
fname = chiakiFS_get_fname(to);
// new dentry
link_dentry = new_dentry(fname, from_dentry->ftype); // Use same type as 'from'
link_dentry->parent = parent_dentry;
link_dentry->ino = from_dentry->ino; // Point to same inode
link_dentry->inode = from_dentry->inode;
// Dentryをparentへ接続
chiakiFS_alloc_dentry(parent_inode, link_dentry, TRUE);
// ディスクへ
chiakiFS_sync_inode(parent_inode);
// リンク元のinodeのリンク数をインクリメントし、同期する
from_dentry->inode->link_cnt++;
chiakiFS_sync_inode(from_dentry->inode);
return CHIAKIFS_ERROR_NONE;
}
chiakiFS_lookup(from, &is_find_from, &is_root_from)
を呼び出して元のパスを検索します。chiakiFS_lookup(to, &is_find_to, &is_root_to)
を呼び出してターゲットパスを検索します。ターゲットパスが既に存在する場合、エラーを返します。
ターゲットパスの親ディレクトリを取得します。新しいdentryを作成し、既存のinodeを指すようにします。新しいdentryを親ディレクトリに追加します。chiakiFS_sync_inode(parent_inode)
を呼び出して親inodeをディスクに同期し、ハードリンクの参照カウント(リンク数)を更新します。
デバッグ
ログレーベルデバッグ
/******************************************************************************
* SECTION: macro debug
*******************************************************************************/
#define CHIAKIFS_DBG(fmt, ...) do { printf("CHIAKIFS_DBG: " fmt, ##__VA_ARGS__); } while(0)
ビットマップデバッグ
void chiakiFS_dump_Imap() {
int byte_cursor = 0;
int bit_cursor = 0;
for (byte_cursor = 0; byte_cursor < CHIAKIFS_BLKS_SZ(chiakiFS_super.map_inode_blks);
byte_cursor+=4)
{
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_inode[byte_cursor] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\t");
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_inode[byte_cursor + 1] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\t");
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_inode[byte_cursor + 2] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\t");
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_inode[byte_cursor + 3] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\n");
}
}
void chiakiFS_dump_Dmap() {
int byte_cursor = 0;
int bit_cursor = 0;
for (byte_cursor = 0; byte_cursor < CHIAKIFS_BLKS_SZ(chiakiFS_super.map_data_blks);
byte_cursor+=4)
{
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_data[byte_cursor] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\t");
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_data[byte_cursor + 1] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\t");
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_data[byte_cursor + 2] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\t");
for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
printf("%d ", (chiakiFS_super.map_data[byte_cursor + 3] & (0x1 << bit_cursor)) >> bit_cursor);
}
printf("\n");
}
}
FUSEで稼働
struct custom_options {
const char* device; // デバイス名
boolean show_help; // ヘルプ表示フラグ
};
/******************************************************************************
* SECTION: マクロ define
*******************************************************************************/
#define OPTION(t, p) { t, offsetof(struct custom_options, p), 1 }
/******************************************************************************
* SECTION: グローバル変数
*******************************************************************************/
static const struct fuse_opt option_spec[] = { /* FUSEのパラメータ解析用 */
OPTION("--device=%s", device),
FUSE_OPT_END
};
struct custom_options chiakiFS_options; /* グローバルオプション */
struct chiakiFS_super chiakiFS_super;
/******************************************************************************
* SECTION: FUSEの入口
*******************************************************************************/
int main(int argc, char **argv)
{
int ret;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
chiakiFS_options.device = strdup(/*ここはご自分のddriverパス*/"/root/ddriver");
if (fuse_opt_parse(&args, &chiakiFS_options, option_spec, NULL) == -1)
return -1;
ret = fuse_main(args.argc, args.argv, &operations, NULL);
fuse_opt_free_args(&args);
return ret;
}
実現された関数一覧
chiakiFS.hの全文:
#ifndef _CHIAKIFS_H_
#define _CHIAKIFS_H_
#define FUSE_USE_VERSION 26
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "fcntl.h"
#include "string.h"
#include "fuse.h"
#include <stddef.h>
#include "ddriver.h"
#include "errno.h"
#include "types.h"
#include "stdint.h"
#define CHIAKIFS_MAGIC 0x20040301 /* TODO: お好きな数字でいい、ファイルシステムのマジックナンバー */
#define CHIAKIFS_DEFAULT_PERM 0777 /* フールアクセス */
/******************************************************************************
* SECTION: macro debug
*******************************************************************************/
#define CHIAKIFS_DBG(fmt, ...) do { printf("CHIAKIFS_DBG: " fmt, ##__VA_ARGS__); } while(0)
/******************************************************************************
* SECTION: chiakiFS_utils.c
*******************************************************************************/
char* chiakiFS_get_fname(const char* path);
int chiakiFS_calc_lvl(const char * path);
int chiakiFS_driver_read(int offset, uint8_t *out_content, int size);
int chiakiFS_driver_write(int offset, uint8_t *in_content, int size);
int chiakiFS_mount(struct custom_options options);
int chiakiFS_umount();
int chiakiFS_alloc_dentry(struct chiakiFS_inode * inode, struct chiakiFS_dentry * dentry, int W);
int chiakiFS_drop_dentry(struct chiakiFS_inode * inode, struct chiakiFS_dentry * dentry);
struct chiakiFS_inode* chiakiFS_alloc_inode(struct chiakiFS_dentry * dentry);
int chiakiFS_sync_inode(struct chiakiFS_inode * inode);
int chiakiFS_drop_inode(struct chiakiFS_inode * inode);
struct chiakiFS_inode* chiakiFS_read_inode(struct chiakiFS_dentry * dentry, int ino);
struct chiakiFS_dentry* chiakiFS_get_dentry(struct chiakiFS_inode * inode, int dir);
struct chiakiFS_dentry* chiakiFS_lookup(const char * path, boolean * is_find, boolean* is_root);
/******************************************************************************
* SECTION: chiakiFS.c
*******************************************************************************/
void* chiakiFS_init(struct fuse_conn_info *);
void chiakiFS_destroy(void *);
int chiakiFS_mkdir(const char *, mode_t);
int chiakiFS_getattr(const char *, struct stat *);
int chiakiFS_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *);
int chiakiFS_mknod(const char *, mode_t, dev_t);
int chiakiFS_write(const char *, const char *, size_t, off_t, struct fuse_file_info *);
int chiakiFS_read(const char *, char *, size_t, off_t, struct fuse_file_info *);
int chiakiFS_access(const char *, int);
int chiakiFS_unlink(const char *);
int chiakiFS_rmdir(const char *);
int chiakiFS_rename(const char *, const char *);
int chiakiFS_utimens(const char *, const struct timespec tv[2]);
int chiakiFS_truncate(const char *, off_t);
int chiakiFS_open(const char *, struct fuse_file_info *);
int chiakiFS_opendir(const char *, struct fuse_file_info *);
int chiakiFS_symlink(const char *, const char *);
int chiakiFS_readlink(const char *, char *, size_t);
int chiakiFS_link(const char *, const char *);
/******************************************************************************
* SECTION: chiakiFS_debug.c
*******************************************************************************/
void chiakiFS_dump_Imap();
void chiakiFS_dump_Dmap();
#endif /* _chiakiFS_H_ */
ディスクレイアウトと他の定数定義
types.hの全文:
#ifndef _TYPES_H_
#define _TYPES_H_
/******************************************************************************
* SECTION: Type def (型定義セクション)
*******************************************************************************/
typedef int boolean; // ブール型をintとして定義
typedef uint16_t flag16; // 16ビットのフラグ型
// ファイルタイプの列挙型定義
typedef enum chiakiFS_file_type {
CHIAKIFS_REG_FILE, // 通常ファイル
CHIAKIFS_DIR, // ディレクトリ
CHIAKIFS_SYM_LINK // シンボリックリンク
} CHIAKIFS_FILE_TYPE;
/******************************************************************************
* SECTION: Macro (マクロ定義セクション)
*******************************************************************************/
#define TRUE 1
#define FALSE 0
#define UINT32_BITS 32
#define UINT8_BITS 8
#define CHIAKIFS_SUPER_OFS 0 // スーパーブロックのオフセット
#define CHIAKIFS_ROOT_INO 0 // ルートinode番号
// Layout用マクロ
#define CHIAKIFS_SUPER_BLKS 1 // スーパーブロックのブロック数
#define CHIAKIFS_MAP_INODE_BLKS 1 // inodeマップのブロック数
#define CHIAKIFS_MAP_DATA_BLKS 1 // データマップのブロック数
#define CHIAKIFS_INODE_PER_BLOCK 6 // ブロックごとのinode数 (Layout)
#define CHIAKIFS_INODE_BLKS 164 // inodeのブロック数
#define CHIAKIFS_DATA_BLKS 3929 // データブロックの数
// エラーコードのマクロ定義
#define CHIAKIFS_ERROR_NONE 0 // エラーなし
#define CHIAKIFS_ERROR_ACCESS EACCES // アクセスエラー
#define CHIAKIFS_ERROR_SEEK ESPIPE // シークエラー
#define CHIAKIFS_ERROR_ISDIR EISDIR // ディレクトリエラー
#define CHIAKIFS_ERROR_NOSPACE ENOSPC // スペース不足エラー
#define CHIAKIFS_ERROR_EXISTS EEXIST // ファイルが既に存在するエラー
#define CHIAKIFS_ERROR_NOTFOUND ENOENT // ファイルが見つからないエラー
#define CHIAKIFS_ERROR_UNSUPPORTED ENXIO // サポートされていないエラー
#define CHIAKIFS_ERROR_IO EIO // 入出力エラー
#define CHIAKIFS_ERROR_INVAL EINVAL // 無効な引数エラー
#define CHIAKIFS_ERROR_NOTDIR ENOTDIR // ディレクトリではないエラー
#define CHIAKIFS_MAX_FILE_NAME 128 // ファイル名の最大長さ
#define CHIAKIFS_INODE_PER_FILE 16 // ファイルごとのinode数 (Layout)
#define CHIAKIFS_DATA_PER_FILE 4 // ファイルごとのデータブロック数 (Layout)
#define CHIAKIFS_DEFAULT_PERM 0777 // デフォルトのパーミッション
#define CHIAKIFS_IOC_MAGIC 'S' // IOCTLのマジック
#define CHIAKIFS_IOC_SEEK _IO(CHIAKIFS_IOC_MAGIC, 0) // IOCTL SEEK
// バッファのフラグ定義
#define CHIAKIFS_FLAG_BUF_DIRTY 0x1 // バッファがダーティ状態
#define CHIAKIFS_FLAG_BUF_OCCUPY 0x2 // バッファが使用中
/******************************************************************************
* SECTION: Macro Function (マクロ関数セクション)
*******************************************************************************/
#define CHIAKIFS_IO_SZ() (chiakiFS_super.sz_io) // IOサイズ取得
#define CHIAKIFS_DISK_SZ() (chiakiFS_super.sz_disk) // ディスクサイズ取得
#define CHIAKIFS_BLK_SZ() (chiakiFS_super.sz_blk) // ブロックサイズ取得
#define CHIAKIFS_DRIVER() (chiakiFS_super.driver_fd) // ドライバ取得
#define CHIAKIFS_DENTRY_PER_DATABLK() (CHIAKIFS_BLK_SZ()/sizeof(struct chiakiFS_dentry)) // データブロックごとのdentry数
#define CHIAKIFS_ROUND_DOWN(value, round) ((value) % (round) == 0 ? (value) : ((value) / (round)) * (round))
#define CHIAKIFS_ROUND_UP(value, round) ((value) % (round) == 0 ? (value) : ((value) / (round) + 1) * (round))
#define CHIAKIFS_BLKS_SZ(blks) ((blks) * CHIAKIFS_BLK_SZ()) // ブロック数からサイズ取得
#define CHIAKIFS_ASSIGN_FNAME(pchiakiFS_dentry, _fname) \
do { \
strncpy((pchiakiFS_dentry)->fname, (_fname), CHIAKIFS_MAX_FILE_NAME - 1); \
(pchiakiFS_dentry)->fname[CHIAKIFS_MAX_FILE_NAME - 1] = '\0'; \
} while(0)
// ファイル名の割り当て
#define CHIAKIFS_INO_OFS(ino) (chiakiFS_super.inode_offset \
+ (ino / CHIAKIFS_INODE_PER_BLOCK) * CHIAKIFS_BLK_SZ() \
+ (ino % CHIAKIFS_INODE_PER_BLOCK) * sizeof(struct chiakiFS_inode_d)) // inodeオフセット計算
#define CHIAKIFS_DATA_OFS(dno) (chiakiFS_super.data_offset + CHIAKIFS_BLKS_SZ(dno)) // データオフセット計算
// inodeのタイプをチェックするマクロ
#define CHIAKIFS_IS_DIR(pinode) (pinode->dentry->ftype == CHIAKIFS_DIR)
#define CHIAKIFS_IS_REG(pinode) (pinode->dentry->ftype == CHIAKIFS_REG_FILE)
#define CHIAKIFS_IS_SYM_LINK(pinode) (pinode->dentry->ftype == CHIAKIFS_SYM_LINK)
/******************************************************************************
* SECTION: FS Specific Structure - In memory structure (ファイルシステム固有構造 - メモリ内構造)
*******************************************************************************/
struct chiakiFS_dentry;
struct chiakiFS_inode;
struct chiakiFS_super;
struct custom_options {
const char* device; // デバイス名
boolean show_help; // ヘルプ表示フラグ
};
struct chiakiFS_inode
{
int ino; // inode番号
int size; // ファイル使用領域サイズ
char target_path[CHIAKIFS_MAX_FILE_NAME]; // シンボリックリンク時のターゲットパス
int dir_cnt; // ディレクトリカウント
uint32_t link_cnt; // リンク数
struct chiakiFS_dentry* dentry; // このinodeへのdentryへのポインタ
struct chiakiFS_dentry* dentrys; // 全てのディレクトリエントリ
uint8_t* data[CHIAKIFS_DATA_PER_FILE]; // データブロック
int dblk[CHIAKIFS_DATA_PER_FILE]; // データブロック番号
};
struct chiakiFS_dentry
{
char fname[CHIAKIFS_MAX_FILE_NAME];// ファイル名
struct chiakiFS_dentry* parent; // 親inodeのdentry
struct chiakiFS_dentry* brother; // 兄弟dentry
int ino; // inode番号
struct chiakiFS_inode* inode; // inodeへのポインタ
CHIAKIFS_FILE_TYPE ftype; // ファイルタイプ
};
struct chiakiFS_super
{
int driver_fd; // ドライバファイルディスクリプタ
int sz_io; // IOサイズ
int sz_disk; // ディスクサイズ
int sz_blk; // ブロックサイズ
int sz_usage; // 使用サイズ
int max_ino; // 最大inode数
uint8_t* map_inode; // inodeマップ
int map_inode_blks; // inodeマップブロック数
int map_inode_offset; // inodeマップオフセット
int inode_offset; // inodeオフセット
int max_data; // 最大データ数
uint8_t* map_data; // データマップ
int map_data_blks; // データマップブロック数
int map_data_offset; // データマップオフセット
int data_offset; // データオフセット
boolean is_mounted; // マウント状態
struct chiakiFS_dentry* root_dentry; // ルートdentryへのポインタ
};
// 新しいdentryを作成する関数
static inline struct chiakiFS_dentry* new_dentry(char * fname, CHIAKIFS_FILE_TYPE ftype) {
struct chiakiFS_dentry * dentry = (struct chiakiFS_dentry *)malloc(sizeof(struct chiakiFS_dentry));
memset(dentry, 0, sizeof(struct chiakiFS_dentry));
CHIAKIFS_ASSIGN_FNAME(dentry, fname);
dentry->ftype = ftype;
dentry->ino = -1;
dentry->inode = NULL;
dentry->parent = NULL;
dentry->brother = NULL;
return dentry;
}
/******************************************************************************
* SECTION: FS Specific Structure - Disk structure (ファイルシステム固有構造 - ディスク構造)
*******************************************************************************/
struct chiakiFS_super_d
{
uint32_t magic_num; // マジックナンバー
uint32_t sz_usage; // 使用サイズ
uint32_t max_ino; // 最大inode数
uint32_t map_inode_blks; // inodeマップブロック数
uint32_t map_inode_offset; // inodeマップオフセット
uint32_t inode_offset; // inodeオフセット
uint32_t max_data; // 最大データ数
uint32_t map_data_blks; // データマップブロック数
uint32_t map_data_offset; // データマップオフセット
uint32_t data_offset; // データオフセット
};
struct chiakiFS_inode_d
{
uint32_t ino; // inodeビットマップのインデックス
uint32_t size; // ファイル使用領域サイズ
char target_path[CHIAKIFS_MAX_FILE_NAME]; // シンボリックリンク時のターゲットパス
uint32_t dir_cnt; // ディレクトリカウント
uint32_t link_cnt; // リンク数
CHIAKIFS_FILE_TYPE ftype; // ファイルタイプ
int dblk[CHIAKIFS_DATA_PER_FILE]; // データブロック番号
};
struct chiakiFS_dentry_d
{
char fname[CHIAKIFS_MAX_FILE_NAME]; // ファイル名
CHIAKIFS_FILE_TYPE ftype; // ファイルタイプ
uint32_t ino; // 指定されたinode番号
};
#endif /* _TYPES_H_ */
テスト
Demo File Systemのテスト
マニュアルテスト
まずはテストファイルを導入
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/demo]
└─# cd tests && ./start.sh && cd ..
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0137056 s, 306 MB/s
ディスクをマウント
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/demo]
└─# ./build/demo -f -d -s -o use_ino ./tests/mnt
他のターミナルで次のコマンドを実行、pass_task1.txtが表示されれば、テストOKです。
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/demo]
└─# cd tests
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/demo/tests]
└─# cd mnt
┌──(root㉿Amamitsu)-[~/…/fs/demo/tests/mnt]
└─# ls
pass_task1.txt
┌──(root㉿Amamitsu)-[~/…/fs/demo/tests/mnt]
└─# cd ..
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/demo/tests]
└─# fusermount -uz mnt
これはディスクのログ
FUSE library version: 2.9.9
nullpath_ok: 0
nopath: 0
utime_omit_ok: 0
unique: 2, opcode: INIT (26), nodeid: 0, insize: 104, pid: 0
INIT: 7.40
flags=0x73fffffb
max_readahead=0x00020000
super.driver_fd: 4
INIT: 7.19
flags=0x00000011
max_readahead=0x00020000
max_write=0x00020000
max_background=0
congestion_threshold=0
unique: 2, success, outsize: 40
unique: 4, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 5292
getattr /
unique: 4, success, outsize: 120
unique: 6, opcode: ACCESS (34), nodeid: 1, insize: 48, pid: 5292
unique: 6, error: -38 (Function not implemented), outsize: 16
unique: 8, opcode: OPENDIR (27), nodeid: 1, insize: 48, pid: 6722
unique: 8, success, outsize: 32
unique: 10, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 6722
getattr /
unique: 10, success, outsize: 120
unique: 12, opcode: READDIR (28), nodeid: 1, insize: 80, pid: 6722
readdir[0] from 0
unique: 12, success, outsize: 56
unique: 14, opcode: LOOKUP (1), nodeid: 1, insize: 55, pid: 6722
LOOKUP /pass_task1.txt
getattr /pass_task1.txt
NODEID: 2
unique: 14, success, outsize: 144
unique: 16, opcode: READDIR (28), nodeid: 1, insize: 80, pid: 6722
unique: 16, success, outsize: 16
unique: 18, opcode: RELEASEDIR (29), nodeid: 1, insize: 64, pid: 0
unique: 18, success, outsize: 16
unique: 20, opcode: LOOKUP (1), nodeid: 1, insize: 42, pid: 5292
LOOKUP /c
getattr /c
NODEID: 3
unique: 20, success, outsize: 144
unique: 22, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 5292
getattr /
unique: 22, success, outsize: 120
unique: 24, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 5292
getattr /
unique: 24, success, outsize: 120
unique: 26, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 5292
getattr /
unique: 26, success, outsize: 120
unique: 28, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 5292
getattr /
unique: 28, success, outsize: 120
オートテスト
demo/testsでtest.shを実行、Test Pass!!!が表示されれば、テストOK。
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/demo]
└─# cd tests && ./test.sh && cd ..
Test Pass!!!
chiakiFSのテスト
オートテスト
chiaki/testsでtest.shを実行、おめでとう、All Test Pass!!!(34/34)が表示されれば、テストOK。
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki]
└─# ./test.sh
テスト方法を選んでください[N(基本機能テスト) / E(エクストラ機能テスト) / S(ステップごとテスト)]: E
テスト:mount, mkdir, touch, ls, read&write, cp, umount
テストスクリプトのディレクトリ: /root/user-land-filesystem/fs/chiaki/tests
テストパック: /root/user-land-filesystem/fs/chiaki/tests/stages/mount.sh
テストパック: /root/user-land-filesystem/fs/chiaki/tests/stages/mkdir.sh
テストパック: /root/user-land-filesystem/fs/chiaki/tests/stages/touch.sh
テストパック: /root/user-land-filesystem/fs/chiaki/tests/stages/ls.sh
テストパック: /root/user-land-filesystem/fs/chiaki/tests/stages/remount.sh
テストパック: /root/user-land-filesystem/fs/chiaki/tests/stages/rw.sh
テストパック: /root/user-land-filesystem/fs/chiaki/tests/stages/cp.sh
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0135117 s, 310 MB/s
================================================================================
pass: case 1 - mount
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.00674529 s, 622 MB/s
================================================================================
pass: case 2.1 - mkdir /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0
pass: case 2.2 - mkdir /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0/dir0
pass: case 2.3 - mkdir /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0/dir0/dir0
pass: case 2.4 - mkdir /root/user-land-filesystem/fs/chiaki/tests/mnt/dir1
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0063167 s, 664 MB/s
================================================================================
pass: case 3.1 - touch /root/user-land-filesystem/fs/chiaki/tests/mnt/file0
pass: case 3.2 - touch /root/user-land-filesystem/fs/chiaki/tests/mnt/file1
pass: case 3.3 - touch /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0/file1
pass: case 3.4 - touch /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0/file2
pass: case 3.5 - touch /root/user-land-filesystem/fs/chiaki/tests/mnt/dir1/file3
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0141014 s, 297 MB/s
================================================================================
pass: case 4.1 - ls /root/user-land-filesystem/fs/chiaki/tests/mnt/
pass: case 4.2 - ls /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0
pass: case 4.3 - ls /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0/dir1
pass: case 4.4 - ls /root/user-land-filesystem/fs/chiaki/tests/mnt/dir0/dir1/dir2
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.01359 s, 309 MB/s
================================================================================
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0147269 s, 285 MB/s
pass: case 5.1 - umount /root/user-land-filesystem/fs/chiaki/tests/mnt
pass: case 5.2 - remount /root/user-land-filesystem/fs/chiaki/tests/mnt
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0139879 s, 300 MB/s
pass: case 5.3 - check bitmap
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0152768 s, 275 MB/s
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0131412 s, 319 MB/s
================================================================================
pass: case 6.1 - write /root/user-land-filesystem/fs/chiaki/tests/mnt/file0
pass: case 6.2 - read /root/user-land-filesystem/fs/chiaki/tests/mnt/file0
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0146024 s, 287 MB/s
================================================================================
pass: case 7.1 - prepare content of /root/user-land-filesystem/fs/chiaki/tests/mnt/file9
pass: case 7.2 - copy /root/user-land-filesystem/fs/chiaki/tests/mnt/file9 to /root/user-land-filesystem/fs/chiaki/tests/mnt/file10
================================================================================
Score: 34/34
pass: おめでとう、All Test Pass!!!(34/34)
マニュアルテスト
上記のオートテストは、mount, mkdir, touch, ls, read&write, cp, umountだけをテストする。
他の機能、つまりエクストラエクストラ機能のテストは、マニュアル的に行う。
まず、ファイルシステムを初期化し、上述した機能をテストするための環境を構築します:
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki]
└─# ddriver -r
ターゲットデバイス /root/ddriver
8192+0 records in
8192+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.00637671 s, 658 MB/s
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki]
└─# ./build/chiakiFS -f -d -o use_ino -s ./tests/mnt
FUSE library version: 2.9.9
nullpath_ok: 0
nopath: 0
utime_omit_ok: 0
unique: 2, opcode: INIT (26), nodeid: 0, insize: 104, pid: 0
INIT: 7.40
flags=0x73fffffb
max_readahead=0x00020000
CHIAKIFS_DBG: inode map blocks: 1
以下の手順でルートディレクトリ~/user-land-filesystem/fs/chiaki/tests/mnt
に設定します:
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─#
touch file.txt
echo "This is file.txt, it is a simple file on the chiakiFS file system. Well there are just 1024 Bytes for this block. Lorem ipsum dolor sit amet, ccccc I do not know." > file.txt
mkdir dir
cd dir
touch 1.asm
echo -e ".text\nLI a0,0xDEADBEEF\nECALL" > 1.asm
cd ..
ln -s dir dir_slink
ln dir/1.asm asm.hlink
これで、追加のテスト環境が構築されました。
次に、各ファイルの基本的な属性を確認することができます。
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# stat .
File: .
Size: 0 Blocks: 4096 IO Block: 1024 directory
Device: 0,62 Inode: 0 Links: 2
Access: (0777/drwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:33:33.000000000 +0800
Modify: 2024-12-10 22:33:33.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# stat file.txt
File: file.txt
Size: 163 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 1 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:33:35.000000000 +0800
Modify: 2024-12-10 22:33:35.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# stat dir
File: dir
Size: 136 Blocks: 0 IO Block: 1024 directory
Device: 0,62 Inode: 2 Links: 2
Access: (0777/drwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:33:38.000000000 +0800
Modify: 2024-12-10 22:33:38.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# stat dir/1.asm
File: dir/1.asm
Size: 29 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 3 Links: 2
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:33:43.000000000 +0800
Modify: 2024-12-10 22:33:43.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# stat dir_slink
File: dir_slink -> dir
Size: 3 Blocks: 0 IO Block: 1024 symbolic link
Device: 0,62 Inode: 4 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:33:50.000000000 +0800
Modify: 2024-12-10 22:33:50.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# stat stat asm.hlink
File: asm.hlink
Size: 29 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 3 Links: 2
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:33:55.000000000 +0800
Modify: 2024-12-10 22:33:55.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
ディレクトリ構造は以下の通りです:
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# ls
asm.hlink dir dir_slink file.txt
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# ls dir
1.asm
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# ls -li
total 0
3 -rwxrwxrwx 2 root root 29 Dec 10 22:33 asm.hlink
2 drwxrwxrwx 2 root root 136 Dec 10 22:33 dir
4 lrwxrwxrwx 1 root root 3 Dec 10 22:33 dir_slink -> dir
1 -rwxrwxrwx 1 root root 163 Dec 10 22:33 file.txt
┌──(root㉿Amamitsu)-[~/user-land-filesystem/fs/chiaki/tests]
└─# ls dir -li
total 0
3 -rwxrwxrwx 2 root root 29 Dec 10 22:34 1.asm
これは、以前に提示したオンディスク構造図と一致しています。
💫ハードリンク
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat dir/1.asm
.text
LI a0,0xDEADBEEF
ECALL
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat asm.hlink
.text
LI a0,0xDEADBEEF
ECALL
機能が正常であることを確認できます。
ファイル内容を変更
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# echo -e "\n.end of .text" >> asm.hlink
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat dir/1.asm
.text
LI a0,0xDEADBEEF
ECALL
.end of .text
機能が本当に正常であることを確認できます。
💫ファイルコピー
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cp dir/1.asm dir/copy.asm
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls dir -li
total 0
3 -rwxrwxrwx 2 root root 44 Dec 10 22:36 1.asm
5 -rwxrwxrwx 1 root root 44 Dec 10 22:36 copy.asm
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat dir/copy.asm
.text
LI a0,0xDEADBEEF
ECALL
.end of .text
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat dir/copy.asm
File: dir/copy.asm
Size: 44 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 5 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:37:09.000000000 +0800
Modify: 2024-12-10 22:37:09.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
新しいファイルとして確認でき、機能が正常です。
💫ファイル名変更
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# mv dir/copy.asm dir/rename.asm
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls dir -li
total 0
3 -rwxrwxrwx 2 root root 44 Dec 10 22:50 1.asm
5 -rwxrwxrwx 1 root root 44 Dec 10 22:50 rename.asm
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat dir/rename.asm
.text
LI a0,0xDEADBEEF
ECALL
.end of .text
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat dir/rename.asm
File: dir/rename.asm
Size: 44 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 5 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:50:26.000000000 +0800
Modify: 2024-12-10 22:50:26.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
機能が正常であることを確認できます。
💫ファイル移動
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cd dir
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# mv rename.asm ../moved.asm
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# ls .. -li
total 0
3 -rwxrwxrwx 2 root root 44 Dec 10 22:51 asm.hlink
2 drwxrwxrwx 2 root root 136 Dec 10 22:51 dir
4 lrwxrwxrwx 1 root root 3 Dec 10 22:51 dir_slink -> dir
1 -rwxrwxrwx 1 root root 163 Dec 10 22:51 file.txt
5 -rwxrwxrwx 1 root root 44 Dec 10 22:51 moved.asm
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# cat ../moved.asm
.text
LI a0,0xDEADBEEF
ECALL
.end of .text
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# stat ../moved.asm
File: ../moved.asm
Size: 44 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 5 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:51:30.000000000 +0800
Modify: 2024-12-10 22:51:30.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
機能が正常であることを確認できます。
💫ファイル削除
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# rm ../moved.asm
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# ls .. -li
total 0
3 -rwxrwxrwx 2 root root 44 Dec 10 22:51 asm.hlink
2 drwxrwxrwx 2 root root 136 Dec 10 22:51 dir
4 lrwxrwxrwx 1 root root 3 Dec 10 22:51 dir_slink -> dir
1 -rwxrwxrwx 1 root root 163 Dec 10 22:51 file.txt
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# cat ../moved.asm
cat: ../moved.asm: No such file or directory
機能が正常であることを確認できます。
💫ソフトリンク
┌──(root㉿Amamitsu)-[~/…/chiaki/tests/mnt/dir]
└─# cd ..
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat dir_slink/1.asm
.text
LI a0,0xDEADBEEF
ECALL
.end of .text
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# echo "Tested" > dir_slink/1.asm
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat dir/1.asm
Tested
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat dir/1.asm
File: dir/1.asm
Size: 7 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 3 Links: 2
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:53:35.000000000 +0800
Modify: 2024-12-10 22:53:35.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat dir_slink/1.asm
File: dir_slink/1.asm
Size: 7 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 3 Links: 2
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:53:42.000000000 +0800
Modify: 2024-12-10 22:53:42.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
機能が正常であることを確認できます。
💫ディレクトリコピー
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cp -r dir directory
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls -li
total 0
3 -rwxrwxrwx 2 root root 7 Dec 10 22:55 asm.hlink
2 drwxrwxrwx 2 root root 136 Dec 10 22:55 dir
4 lrwxrwxrwx 1 root root 3 Dec 10 22:55 dir_slink -> dir
5 drwxrwxrwx 2 root root 136 Dec 10 22:55 directory
1 -rwxrwxrwx 1 root root 163 Dec 10 22:55 file.txt
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat dir
File: dir
Size: 136 Blocks: 0 IO Block: 1024 directory
Device: 0,62 Inode: 2 Links: 2
Access: (0777/drwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:55:08.000000000 +0800
Modify: 2024-12-10 22:55:08.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat directory
File: directory
Size: 136 Blocks: 0 IO Block: 1024 directory
Device: 0,62 Inode: 5 Links: 2
Access: (0777/drwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:55:13.000000000 +0800
Modify: 2024-12-10 22:55:13.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat dir/1.asm
File: dir/1.asm
Size: 7 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 3 Links: 2
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:55:19.000000000 +0800
Modify: 2024-12-10 22:55:19.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat directory/1.asm
File: directory/1.asm
Size: 7 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 6 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:55:23.000000000 +0800
Modify: 2024-12-10 22:55:23.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
ファイルを比較、機能が正常で、内部のファイルが新しいことを確認できます。
💫ディレクトリ名変更
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# mv directory direname
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls -li
total 0
3 -rwxrwxrwx 2 root root 7 Dec 10 22:56 asm.hlink
2 drwxrwxrwx 2 root root 136 Dec 10 22:56 dir
4 lrwxrwxrwx 1 root root 3 Dec 10 22:56 dir_slink -> dir
5 drwxrwxrwx 2 root root 136 Dec 10 22:56 direname
1 -rwxrwxrwx 1 root root 163 Dec 10 22:56 file.txt
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat direname/1.asm
Tested
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls direname -li
total 0
6 -rwxrwxrwx 1 root root 7 Dec 10 22:56 1.asm
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat direname
File: direname
Size: 136 Blocks: 0 IO Block: 1024 directory
Device: 0,62 Inode: 5 Links: 2
Access: (0777/drwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:56:55.000000000 +0800
Modify: 2024-12-10 22:56:55.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat direname/1.asm
File: direname/1.asm
Size: 7 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 6 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:56:58.000000000 +0800
Modify: 2024-12-10 22:56:58.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
機能が正常であることを確認できます。
💫ディレクトリ移動
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# mv direname dir
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls
asm.hlink dir dir_slink file.txt
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls dir -li
total 0
3 -rwxrwxrwx 2 root root 7 Dec 10 22:57 1.asm
5 drwxrwxrwx 2 root root 136 Dec 10 22:57 direname
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat dir/direname/1.asm
Tested
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat dir/direname/1.asm
File: dir/direname/1.asm
Size: 7 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 6 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 22:57:54.000000000 +0800
Modify: 2024-12-10 22:57:54.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
機能が正常であることを確認できます。
💫ディレクトリ削除
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# rm -r dir
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls -li
total 0
3 -rwxrwxrwx 1 root root 7 Dec 10 22:58 asm.hlink
4 lrwxrwxrwx 1 root root 3 Dec 10 22:58 dir_slink -> dir
1 -rwxrwxrwx 1 root root 163 Dec 10 22:58 file.txt
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cd dir_slink
cd: no such file or directory: dir_slink
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat asm.hlink
Tested
ディレクトリが削除され、デッドリンクが発生。機能が正常であることを確認できます。
また、以前に作成したハードリンクにアクセスすると、データが取得でき、参照カウントが1に減少しました。これにより、ハードリンク設計の正確性が再び証明されました。
💫vimでのファイル読み書き:
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# vim file.txt
[input as following]
[I]
This is file.txt, it is a simple file on the chiakiFS file system. Well there are just 1024 Bytes for this block. Lorem ipsum dolor sit amet, ccccc I do not know.
[Esc][:][w][q][Enter][y]
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# cat file.txt
This is file.txt, it is a simple file on the chiakiFS file system. Well there are just 1024 Bytes for this block. Lorem ipsum dolor sit amet, ccccc I do not knowThis is file.txt, it is a simple file on the chiakiFS file system. Well there are just 1024 Bytes for this block. Lorem ipsum dolor sit amet, ccccc I do not know..
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# stat file.txt
File: file.txt
Size: 325 Blocks: 0 IO Block: 1024 regular file
Device: 0,62 Inode: 5 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-12-10 23:01:27.000000000 +0800
Modify: 2024-12-10 23:01:27.000000000 +0800
Change: 1970-01-01 08:00:00.000000000 +0800
Birth: -
┌──(root㉿Amamitsu)-[~/…/fs/chiaki/tests/mnt]
└─# ls -li
total 0
3 -rwxrwxrwx 1 root root 7 Dec 10 23:01 asm.hlink
4 lrwxrwxrwx 1 root root 3 Dec 10 23:01 dir_slink -> dir
5 -rwxrwxrwx 1 root root 325 Dec 10 23:01 file.txt
機能が正常であることを確認できます。
また、Visual Studio Codeによるファイル書き込み動作も正常であることが確認できるため、ここでは詳細を割愛します。
以上です
コメント