Advent Calendar 2019: advfs
Day 7: 作成したファイルの読み書き
やることは4日目とほとんど同じです。4日目にグローバル変数で管理していたファイル属性をファイルエントリで管理するようになったくらいです。
getattr
ファイル属性を取得する advfs_getattr()
関数のファイル属性を返す部分を以下のように変更します。単純にファイルエントリの情報をコピーするだけでOKです。
} else if ( e->type == ADVFS_REGULAR_FILE ) {
stbuf->st_mode = S_IFREG | e->mode;
stbuf->st_nlink = 1;
stbuf->st_uid = ctx->uid;
stbuf->st_gid = ctx->gid;
status = 0;
stbuf->st_atime = e->atime;
stbuf->st_mtime = e->mtime;
stbuf->st_ctime = e->ctime;
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
stbuf->st_birthtime = e->ctime;
#endif
stbuf->st_rdev = 0;
stbuf->st_size = e->u.file.size;
stbuf->st_blksize = 4096;
stbuf->st_blocks = (e->u.file.size + 4095) / 4096;
} else {
read
基本的には4日目の内容そのままなのですが,ディレクトリの場合(ファイルでない場合)には -EISDIR
エラーを返します。以下に advfs_read()
関数の実装を掲載します。
int
advfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
struct fuse_context *ctx;
advfs_t *advfs;
advfs_entry_t *e;
int perm;
/* Get the context */
ctx = fuse_get_context();
advfs = ctx->private_data;
e = advfs_path2ent(advfs, path, 0);
if ( NULL == e ) {
return -ENOENT;
}
if ( e->type != ADVFS_REGULAR_FILE ) {
return -EISDIR;
}
/* Mode check */
perm = fi->flags & 3;
if ( perm != O_RDONLY && perm != O_RDWR ) {
return -EACCES;
}
if ( offset < (off_t)e->u.file.size ) {
if ( offset + size > e->u.file.size ) {
size = e->u.file.size - offset;
}
(void)memcpy(buf, e->u.file.buf + offset, size);
} else {
size = 0;
}
return size;
}
write
write
API では,read
API よりも多少やることが増えます。4日目ではファイルの最大サイズのメモリを予め確保しましたが,今回は動的に割り当てます。以下のように realloc()
でファイルサイズと同じメモリサイズに割り当て直しています。
int
advfs_write(const char *path, const char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
struct fuse_context *ctx;
advfs_t *advfs;
advfs_entry_t *e;
int perm;
size_t nsize;
uint8_t *nbuf;
/* Get the context */
ctx = fuse_get_context();
advfs = ctx->private_data;
e = advfs_path2ent(advfs, path, 0);
if ( NULL == e ) {
return -ENOENT;
}
if ( e->type != ADVFS_REGULAR_FILE ) {
return -EISDIR;
}
/* Mode check */
perm = fi->flags & 3;
if ( perm != O_WRONLY && perm != O_RDWR ) {
return -EACCES;
}
if ( size <= 0 ) {
return 0;
}
nsize = offset + size;
if ( nsize > e->u.file.size ) {
/* Reallocate */
nbuf = realloc(e->u.file.buf, nsize);
if ( NULL == nbuf ) {
return -EDQUOT;
}
e->u.file.buf = nbuf;
e->u.file.size = nsize;
}
(void)memcpy(e->u.file.buf + offset, buf, size);
return size;
}
truncate
truncate
API も write
API と同様に,以下のように realloc()
関数により,ファイルの実体のメモリを truncate するサイズに合わせ動的に割り当て直します。
int
advfs_truncate(const char *path, off_t size)
{
struct fuse_context *ctx;
advfs_t *advfs;
advfs_entry_t *e;
uint8_t *nbuf;
/* Get the context */
ctx = fuse_get_context();
advfs = ctx->private_data;
e = advfs_path2ent(advfs, path, 0);
if ( NULL == e ) {
return -ENOENT;
}
if ( e->type != ADVFS_REGULAR_FILE ) {
return -EISDIR;
}
if ( (off_t)e->u.file.size != size ) {
if ( size > 0 ) {
nbuf = realloc(e->u.file.buf, size);
if ( NULL == nbuf ) {
return -EFBIG;
}
e->u.file.buf = nbuf;
} else {
free(e->u.file.buf);
e->u.file.buf = NULL;
}
}
while ( (off_t)e->u.file.size < size ) {
e->u.file.buf[e->u.file.size] = 0;
e->u.file.size++;
}
e->u.file.size = size;
return 0;
}
この時点での具体的な実装は src/main.c を参照してください。
実行
昨日同様に実装したプログラムをビルド・実行するために
$ docker-compose build && docker-compose up -d
を実行し,
$ docker exec -it advfs_advfs_1 bash
と実行することで, /mnt
に実装したファイルシステムをマウントしたコンテナで bash
を実行できます。
以下のように /mnt/test
に対して echo
コマンドの出力をリダイレクトし, cat
コマンドで出力することで,ファイルの読み書きが正常に行われていることが確認できます。
root@8cc941723b56:/usr/src# ls -al /mnt/
total 4
drwxrwxrwx 2 root root 0 Dec 7 15:09 .
drwxr-xr-x 1 root root 4096 Dec 7 15:09 ..
root@8cc941723b56:/usr/src# echo "test1234" > /mnt/test
root@8cc941723b56:/usr/src# ls -al /mnt/
total 5
drwxrwxrwx 3 root root 0 Dec 7 15:09 .
drwxr-xr-x 1 root root 4096 Dec 7 15:09 ..
-rw-r--r-- 1 root root 9 Dec 7 15:09 test
root@8cc941723b56:/usr/src# cat /mnt/test
test1234
root@8cc941723b56:/usr/src# echo "test56789" >> /mnt/test
root@8cc941723b56:/usr/src# ls -al /mnt/
total 5
drwxrwxrwx 3 root root 0 Dec 7 15:09 .
drwxr-xr-x 1 root root 4096 Dec 7 15:09 ..
-rw-r--r-- 1 root root 19 Dec 7 15:09 test
root@8cc941723b56:/usr/src# cat /mnt/test
test1234
test56789
root@8cc941723b56:/usr/src# echo "a" > /mnt/test
root@8cc941723b56:/usr/src# ls -al /mnt/
total 5
drwxrwxrwx 3 root root 0 Dec 7 15:09 .
drwxr-xr-x 1 root root 4096 Dec 7 15:09 ..
-rw-r--r-- 1 root root 2 Dec 7 15:09 test
root@8cc941723b56:/usr/src# cat /mnt/test
a
今日のまとめと明日の予定
今日は作成したファイルに対する読み書きを実装しました。明日はファイルの削除やディレクトリの追加を実装しようと思います。