#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>
#include <sys/param.h>
#include <machine/bfs.h>
#include <machine/sector.h>
#include "local.h"
FS_DEF(bfs);
struct fs_ops bfs_ops = {
bfs_open, bfs_close, bfs_read, bfs_write, bfs_seek, bfs_stat
};
struct bfs_file {
struct bfs *bfs;
int start, end;
size_t size;
int cur;
uint8_t buf[DEV_BSIZE];
};
int
bfs_open(const char *name, struct open_file *f)
{
struct bfs_file *file;
if ((file = alloc(sizeof *file)) == 0)
return -1;
memset(file, 0, sizeof *file);
if (bfs_init(&file->bfs) != 0) {
dealloc(file, sizeof *file);
return -2;
}
if (!bfs_file_lookup(file->bfs, name, &file->start, &file->end,
&file->size)) {
bfs_fini(file->bfs);
dealloc(file, sizeof *file);
return -3;
}
printf("%s: %s %d %d %d\n", __func__, name, file->start,
file->end, file->size);
f->f_fsdata = file;
return 0;
}
int
bfs_close(struct open_file *f)
{
struct bfs_file *file = f->f_fsdata;
bfs_fini(file->bfs);
return 0;
}
int
bfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
{
struct bfs_file *file = f->f_fsdata;
int n, start, end;
uint8_t *p = buf;
size_t bufsz = size;
int cur = file->cur;
if (cur + size > file->size)
size = file->size - cur;
start = file->start + (cur >> DEV_BSHIFT);
end = file->start + ((cur + size) >> DEV_BSHIFT);
if (!sector_read(0, file->buf, start))
return -2;
n = TRUNC_SECTOR(cur) + DEV_BSIZE - cur;
if (n >= size) {
memcpy(p, file->buf + DEV_BSIZE - n, size);
goto done;
}
memcpy(p, file->buf + DEV_BSIZE - n, n);
p += n;
if ((end - start - 1) > 0) {
if (!sector_read_n(0, p, start + 1, end - start - 1))
return -2;
p += (end - start - 1) * DEV_BSIZE;
}
if (!sector_read(0, file->buf, end))
return -2;
n = cur + size - TRUNC_SECTOR(cur + size);
memcpy(p, file->buf, n);
done:
file->cur += size;
if (resid)
*resid = bufsz - size;
return 0;
}
int
bfs_write(struct open_file *f, void *start, size_t size, size_t *resid)
{
return -1;
}
off_t
bfs_seek(struct open_file *f, off_t offset, int where)
{
struct bfs_file *file = f->f_fsdata;
int cur;
switch (where) {
case SEEK_SET:
cur = offset;
break;
case SEEK_CUR:
cur = file->cur + offset;
break;
case SEEK_END:
cur = file->size + offset;
break;
default:
return EINVAL;
}
if (cur < 0 || cur >= file->size) {
return EINVAL;
}
file->cur = cur;
return (off_t)cur;
}
int
bfs_stat(struct open_file *f, struct stat *stat)
{
struct bfs_file *file = f->f_fsdata;
stat->st_size = file->size;
return 0;
}