1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/fs/constfs/constfs.c
Frederik Haxel 64ba553d1f sys: Use size_t print format specifier
Co-authored-by: Marian Buschsieweke <marian.buschsieweke@posteo.net>
2023-12-21 12:02:19 +01:00

256 lines
7.7 KiB
C

/*
* Copyright (C) 2016 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_fs_constfs
* @{
*
* @file
* @brief ConstFS implementation
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
* @}
*/
/* Required for strnlen in string.h, when building with -std=c99 */
#define _DEFAULT_SOURCE 1
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "architecture.h"
#include "fs/constfs.h"
#include "vfs.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/* File system operations */
static int constfs_stat(vfs_mount_t *mountp, const char *restrict name, struct stat *restrict buf);
static int constfs_statvfs(vfs_mount_t *mountp, const char *restrict path, struct statvfs *restrict buf);
/* File operations */
static int constfs_fstat(vfs_file_t *filp, struct stat *buf);
static off_t constfs_lseek(vfs_file_t *filp, off_t off, int whence);
static int constfs_open(vfs_file_t *filp, const char *name, int flags, mode_t mode);
static ssize_t constfs_read(vfs_file_t *filp, void *dest, size_t nbytes);
/* Directory operations */
static int constfs_opendir(vfs_DIR *dirp, const char *dirname);
static int constfs_readdir(vfs_DIR *dirp, vfs_dirent_t *entry);
static const vfs_file_system_ops_t constfs_fs_ops = {
.statvfs = constfs_statvfs,
.stat = constfs_stat,
};
static const vfs_file_ops_t constfs_file_ops = {
.fstat = constfs_fstat,
.lseek = constfs_lseek,
.open = constfs_open,
.read = constfs_read,
};
static const vfs_dir_ops_t constfs_dir_ops = {
.opendir = constfs_opendir,
.readdir = constfs_readdir,
};
const vfs_file_system_t constfs_file_system = {
.f_op = &constfs_file_ops,
.fs_op = &constfs_fs_ops,
.d_op = &constfs_dir_ops,
};
/**
* @internal
* @brief Fill a file information struct with information about the file
* pointed to by @p fp
*
* @param[in] fp file to query
* @param[out] buf output buffer
*/
static void _constfs_write_stat(const constfs_file_t *fp, struct stat *restrict buf);
static int constfs_stat(vfs_mount_t *mountp, const char *restrict name, struct stat *restrict buf)
{
(void) name;
/* Fill out some information about this file */
if (buf == NULL) {
return -EFAULT;
}
constfs_t *fs = mountp->private_data;
/* linear search through the files array */
for (size_t i = 0; i < fs->nfiles; ++i) {
DEBUG("constfs_stat ? \"%s\"\n", fs->files[i].path);
if (strcmp(fs->files[i].path, name) == 0) {
DEBUG("constfs_stat: Found :)\n");
_constfs_write_stat(&fs->files[i], buf);
buf->st_ino = i;
return 0;
}
}
DEBUG("constfs_stat: Not found :(\n");
return -ENOENT;
}
static int constfs_statvfs(vfs_mount_t *mountp, const char *restrict path, struct statvfs *restrict buf)
{
(void) path;
/* Fill out some information about this file system */
if (buf == NULL) {
return -EFAULT;
}
constfs_t *fs = mountp->private_data;
/* clear out the stat buffer first */
buf->f_bsize = sizeof(uint8_t); /* block size */
buf->f_frsize = sizeof(uint8_t); /* fundamental block size */
fsblkcnt_t f_blocks = 0;
for (size_t i = 0; i < fs->nfiles; ++i) {
f_blocks += fs->files[i].size;
}
buf->f_blocks = f_blocks; /* Blocks total */
buf->f_bfree = 0; /* Blocks free */
buf->f_bavail = 0; /* Blocks available to non-privileged processes */
buf->f_files = fs->nfiles; /* Total number of file serial numbers */
buf->f_ffree = 0; /* Total number of free file serial numbers */
buf->f_favail = 0; /* Number of file serial numbers available to non-privileged process */
buf->f_fsid = 0; /* File system id */
buf->f_flag = (ST_RDONLY | ST_NOSUID); /* File system flags */
buf->f_namemax = UINT8_MAX; /* Maximum file name length */
return 0;
}
static int constfs_fstat(vfs_file_t *filp, struct stat *buf)
{
constfs_file_t *fp = filp->private_data.ptr;
if (buf == NULL) {
return -EFAULT;
}
_constfs_write_stat(fp, buf);
return 0;
}
static off_t constfs_lseek(vfs_file_t *filp, off_t off, int whence)
{
constfs_file_t *fp = filp->private_data.ptr;
switch (whence) {
case SEEK_SET:
break;
case SEEK_CUR:
off += filp->pos;
break;
case SEEK_END:
off += fp->size;
break;
default:
return -EINVAL;
}
if (off < 0) {
/* the resulting file offset would be negative */
return -EINVAL;
}
/* POSIX allows seeking past the end of the file, even with O_RDONLY */
filp->pos = off;
return off;
}
static int constfs_open(vfs_file_t *filp, const char *name, int flags, mode_t mode)
{
(void) mode;
constfs_t *fs = filp->mp->private_data;
DEBUG("constfs_open: %p, \"%s\", 0x%x, 0%03lo\"\n", (void *)filp, name, flags, (unsigned long)mode);
/* We only support read access */
if ((flags & O_ACCMODE) != O_RDONLY) {
return -EROFS;
}
/* linear search through the files array */
for (size_t i = 0; i < fs->nfiles; ++i) {
DEBUG("constfs_open ? \"%s\"\n", fs->files[i].path);
if (strcmp(fs->files[i].path, name) == 0) {
DEBUG("constfs_open: Found :)\n");
filp->private_data.ptr = (void *)&fs->files[i];
return 0;
}
}
DEBUG("constfs_open: Not found :(\n");
return -ENOENT;
}
static ssize_t constfs_read(vfs_file_t *filp, void *dest, size_t nbytes)
{
constfs_file_t *fp = filp->private_data.ptr;
DEBUG("constfs_read: %p, %p, %" PRIuSIZE "\n", (void *)filp, dest, nbytes);
if ((size_t)filp->pos >= fp->size) {
/* Current offset is at or beyond end of file */
return 0;
}
if (nbytes > (fp->size - filp->pos)) {
nbytes = fp->size - filp->pos;
}
memcpy(dest, (const uint8_t *)fp->data + filp->pos, nbytes);
DEBUG("constfs_read: read %" PRIuSIZE " bytes\n", nbytes);
filp->pos += nbytes;
return nbytes;
}
static int constfs_opendir(vfs_DIR *dirp, const char *dirname)
{
DEBUG("constfs_opendir: %p, \"%s\"\n", (void *)dirp, dirname);
if (strncmp(dirname, "/", 2) != 0) {
/* We keep it simple and only support a flat file system, only a root directory */
return -ENOENT;
}
dirp->private_data.value = 0;
return 0;
}
static int constfs_readdir(vfs_DIR *dirp, vfs_dirent_t *entry)
{
DEBUG("constfs_readdir: %p, %p\n", (void *)dirp, (void *)entry);
constfs_t *fs = dirp->mp->private_data;
int filenum = dirp->private_data.value;
if ((size_t)filenum >= fs->nfiles) {
/* End of stream */
return 0;
}
const constfs_file_t *fp = &fs->files[filenum];
if (fp->path == NULL) {
return -EIO;
}
const char *filename = fp->path[0] == '/' ? fp->path + 1 : fp->path;
size_t len = strnlen(filename, VFS_NAME_MAX + 1);
if (len > VFS_NAME_MAX) {
/* name does not fit in vfs_dirent_t buffer */
/* skipping past the broken entry */
++filenum;
dirp->private_data.value = filenum;
return -EAGAIN;
}
/* copy the string, including terminating null */
memcpy(&entry->d_name[0], filename, len + 1);
entry->d_ino = filenum;
++filenum;
dirp->private_data.value = filenum;
return 1;
}
static void _constfs_write_stat(const constfs_file_t *fp, struct stat *restrict buf)
{
/* buffer is cleared by vfs already */
buf->st_nlink = 1;
buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
buf->st_size = fp->size;
buf->st_blocks = fp->size;
buf->st_blksize = sizeof(uint8_t);
}