Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

meterfs: Implement mount, getAttr, setAttr, stat and readdir #119

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
313 changes: 283 additions & 30 deletions meterfs/meterfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#include <string.h>
#include <stddef.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <dirent.h>
#include <poll.h>
#include <sys/statvfs.h>

#include "meterfs.h"
#include "files.h"
Expand All @@ -37,6 +42,8 @@
#define JOURNAL_OFFSET(ssz) (2 * HEADER_SIZE(ssz))
#define SPARE_SECTOR_OFFSET(ssz) (JOURNAL_OFFSET(ssz) + (ssz))

#define ROOTDIR_ID 0

#define UNRELIABLE_WRITE 0 /* DEBUG ONLY! */
#if UNRELIABLE_WRITE
static struct {
Expand Down Expand Up @@ -740,7 +747,7 @@
break;
}

err = node_add(&f, (id_t)i, &ctx->nodesTree);
err = node_add(&f, (id_t)(ROOTDIR_ID + 1 + i), &ctx->nodesTree);
if (err < 0) {
ret = err;
break;
Expand Down Expand Up @@ -920,49 +927,75 @@

int meterfs_open(id_t id, meterfs_ctx_t *ctx)
{
if (node_getById(id, &ctx->nodesTree) != NULL)
if ((id == ROOTDIR_ID) || (node_getById(id, &ctx->nodesTree) != NULL)) {
return 0;
}

return -ENOENT;
}


int meterfs_close(id_t id, meterfs_ctx_t *ctx)
{
if (node_getById(id, &ctx->nodesTree) != NULL)
if ((id == ROOTDIR_ID) || (node_getById(id, &ctx->nodesTree) != NULL)) {
return 0;
}

return -ENOENT;
}


int meterfs_lookup(const char *name, id_t *res, meterfs_ctx_t *ctx)
int meterfs_lookupOid(const char *name, oid_t *res, meterfs_ctx_t *ctx)

Check failure on line 948 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

unknown type name 'oid_t'; did you mean 'id_t'?
{
file_t f;
char bname[sizeof(f.header.name)];
int i = 0;
size_t j, len = strnlen(&name[1], sizeof(f.header.name) + 1);

if (len < 1 || len > sizeof(f.header.name))
return -EINVAL;
size_t len = 0;

if (name[0] == '/')
++i;
while (name[len] != '\0') {
while (name[len] == '/') {
++len;
}

for (j = 0; j < sizeof(bname); ++j, ++i) {
bname[j] = name[i];
if (name[len] == '\0') {
break;
}

if (name[i] == '/')
return -ENOENT;
char *end = strchrnul(name + len, '/');
const size_t size = end - name + len;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should be:

Suggested change
const size_t size = end - name + len;
const size_t size = end - (name + len);

if ((strncmp(name + len, "..", size) == 0)) {
if (ctx->mountpoint != NULL) {
*res = ctx->parent;
return len - 1;
}
else {
res->id = ROOTDIR_ID;
len += size;
continue;
}
}
else if ((strncmp(name + len, ".", size) == 0)) {
res->id = ROOTDIR_ID;
len += size;
continue;
}
else {
if (node_getByName(name + len, &res->id, &ctx->nodesTree) == NULL) {
return -ENOENT;
}

if (name[i] == '\0')
break;
return len + size;
}
}

if (node_getByName(bname, res, &ctx->nodesTree) == NULL)
return -ENOENT;
return -ENOENT;
}

return i;

/* Backward compatibility, remove after adapting all flashsrvs */
int meterfs_lookup(const char *name, id_t *res, meterfs_ctx_t *ctx)
{
oid_t oid;

Check failure on line 995 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

unknown type name 'oid_t'; did you mean 'id_t'?
int ret = meterfs_lookupOid(name, &oid, ctx);

Check warning on line 996 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

implicit declaration of function 'meterfs_lookupOid'; did you mean 'meterfs_lookup'? [-Wimplicit-function-declaration]
*res = oid.id;

Check failure on line 997 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

request for member 'id' in something not a structure or union
return ret;
}


Expand Down Expand Up @@ -1099,7 +1132,7 @@

meterfs_powerCtrl(0, ctx);

err = node_add(&f, (id_t)ctx->filecnt, &ctx->nodesTree);
err = node_add(&f, (id_t)(ROOTDIR_ID + 1 + ctx->filecnt), &ctx->nodesTree);
if (err < 0)
return err;

Expand Down Expand Up @@ -1315,9 +1348,229 @@
}


int meterfs_setAttr(id_t id, int type, long long int attr, const void *data, size_t size, meterfs_ctx_t *ctx)
{
int ret = 0;
file_t *f = node_getById(id, &ctx->nodesTree);

if ((id == ROOTDIR_ID) || (f != NULL)) {
switch (type) {
case atUid:

Check failure on line 1358 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

'atUid' undeclared (first use in this function)
case atGid:

Check failure on line 1359 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

'atGid' undeclared (first use in this function)
case atMode:

Check failure on line 1360 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

'atMode' undeclared (first use in this function)
case atMTime:

Check failure on line 1361 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

'atMTime' undeclared (first use in this function)
case atATime:

Check failure on line 1362 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

'atATime' undeclared (first use in this function)
/* Ignore */
ret = 0;
break;

case atDev:
case atSize:
/* Not supported explicitly */
ret = -ENOSYS;
break;

default:
ret = -EINVAL;
break;
}
}
else {
ret = -ENOENT;
}

return ret;
}


static inline size_t meterfs_size2block(size_t size)
{
return (size + S_BLKSIZE - 1) / S_BLKSIZE;
}


int meterfs_getAttr(id_t id, int type, long long int *attr, meterfs_ctx_t *ctx)
{
int ret = 0;
file_t *f = node_getById(id, &ctx->nodesTree);

if ((id == ROOTDIR_ID) || (f != NULL)) {
switch (type) {
case atUid:
case atGid:
*attr = 0;
break;

case atMode:
*attr = DEFFILEMODE;
break;

case atSize:
*attr = (id == ROOTDIR_ID) ? 0 : f->recordcnt * (f->header.recordsz);
break;

case atBlocks:
*attr = (id == ROOTDIR_ID) ? 0 : meterfs_size2block(f->header.sectorcnt * ctx->sectorsz);
break;

case atIOBlock:
*attr = (id == ROOTDIR_ID) ? 0 : ctx->sectorsz;
break;

case atType:
/* Handle fs rootdir, otherwise regular file */
/* TODO - remove redundant custom enums */
*attr = (id == ROOTDIR_ID) ? otDir : otFile;
break;

case atCTime:
case atMTime:
case atATime:
*attr = 0;
break;

case atLinks:
*attr = 1;
break;

case atPollStatus:
/* Always ready */
*attr = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
break;

default:
ret = -EINVAL;
break;
}
}
else {
ret = -ENOENT;
}

return ret;
}


int meterfs_readdir(id_t dir, off_t offs, struct dirent *dent, unsigned int size, meterfs_ctx_t *ctx)
{
if (dir != ROOTDIR_ID) {
/* Only rootdir support */
return -ENOENT;
}

if (offs < 0) {
return -EINVAL;
}

/* Hack-ish - handle virtual "." and ".." */
if (offs == 0) { /* "."" */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (offs == 0) { /* "."" */
if (offs == 0) { /* "." */

same in line 1476

if (size < 2) {
return -EINVAL;
}
dent->d_ino = ROOTDIR_ID;
dent->d_reclen = 1;
dent->d_namlen = 1;
dent->d_type = DT_DIR;
strcpy(dent->d_name, ".");
}
else if (offs == 1) { /* ".."" */
if (size < 3) {
return -EINVAL;
}
dent->d_ino = (unsigned long)-1;
dent->d_reclen = 2;
dent->d_namlen = 2;
dent->d_type = DT_DIR;
strcpy(dent->d_name, "..");
}
else {
if (offs < 3) {
return -EINVAL;
}

id_t id;
/* Adjust offset to space taken by "." and ".." */
file_t *f = node_getByOffset(offs - 3, &id, &ctx->nodesTree);
if (f == NULL) {
return -ENOENT;
}

size_t len = strnlen(f->header.name, sizeof(f->header.name));
if ((sizeof(struct dirent) + len + 1) > size) {
return -EINVAL;
}

dent->d_ino = id;
dent->d_reclen = len;
dent->d_namlen = len;
dent->d_type = DT_REG;
strncpy(dent->d_name, f->header.name, len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should be faster

Suggested change
strncpy(dent->d_name, f->header.name, len);
memcpy(dent->d_name, f->header.name, len);

dent->d_name[len] = '\0';
}

return 0;
}


int meterfs_stat(void *buf, size_t len, meterfs_ctx_t *ctx)
{
struct statvfs *st = buf;

st->f_bsize = ctx->sectorsz;
st->f_frsize = st->f_bsize;
st->f_blocks = ctx->sz / ctx->sectorsz;
st->f_bavail = st->f_blocks - (node_totalSectors(&ctx->nodesTree) + (HEADER_SECTOR_CNT * 2));
st->f_bfree = st->f_bavail;
st->f_files = ctx->filecnt + 2; /* files + "." + ".." */
st->f_ffree = MAX_FILE_CNT(ctx->sectorsz) - ctx->filecnt;
st->f_favail = st->f_ffree;
st->f_fsid = (unsigned long)ctx; /* TODO: filesystem ID should be generated at mount time */
st->f_flag = ctx->mountopt;
st->f_namemax = sizeof(((fileheader_t *)0)->name);

return 0;
}


int meterfs_mount(meterfs_ctx_t *ctx, const char *data, unsigned long mode)
{
ctx->mountopt = mode;

if (data == NULL) {
return -EINVAL;
}

ctx->mountpoint = resolve_path(data, NULL, 1, 0);

Check warning on line 1543 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

implicit declaration of function 'resolve_path' [-Wimplicit-function-declaration]

Check warning on line 1543 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

assignment to 'char *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
if (ctx->mountpoint == NULL) {
return -ENOMEM;
}

size_t mntlen = strlen(ctx->mountpoint);
char *parent = malloc(mntlen + 3 + 1);
if (parent == NULL) {
return -ENOMEM;
}
memcpy(parent, ctx->mountpoint, mntlen + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a little faster

Suggested change
memcpy(parent, ctx->mountpoint, mntlen + 1);
memcpy(parent, ctx->mountpoint, mntlen);

strcpy(parent + mntlen, "/..");
int ret = lookup(parent, &ctx->parent, NULL);

Check warning on line 1555 in meterfs/meterfs.c

View workflow job for this annotation

GitHub Actions / call-ci / build (host-generic-pc)

implicit declaration of function 'lookup' [-Wimplicit-function-declaration]
free(parent);
if (ret < 0) {
return -ENOENT;
}

void *mountPoint = realloc(ctx->mountpoint, mntlen + 1);
if (mountPoint == NULL) {
return -ENOMEM;
}
ctx->mountpoint = mountPoint;

return 0;
}


int meterfs_init(meterfs_ctx_t *ctx)
{
int err;
ctx->mountpoint = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move it after checking the condition ctx == NULL


#if UNRELIABLE_WRITE
LOG_INFO("meterfs UNRELIABLE_WRITE is ON. Did you really intend that?");
Expand All @@ -1334,14 +1587,14 @@

node_init(&ctx->nodesTree);

err = meterfs_checkfs(ctx);
if (err < 0) {
return err;
int ret = meterfs_checkfs(ctx);
if (ret < 0) {
return ret;
}

err = meterfs_rbTreeFill(ctx);
if (err < 0) {
return err;
ret = meterfs_rbTreeFill(ctx);
if (ret < 0) {
return ret;
}

LOG_INFO("meterfs: Filesystem check done. Found %u files.", ctx->filecnt);
Expand Down
Loading
Loading