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

sys/vfs_util: add VFS helper functions #18038

Merged
merged 2 commits into from
May 17, 2022
Merged
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
4 changes: 4 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,10 @@ ifneq (,$(filter vfs_default,$(USEMODULE)))
DEFAULT_MODULE += vfs_auto_mount
endif

ifneq (,$(filter vfs_util,$(USEMODULE)))
USEMODULE += vfs
endif

ifneq (,$(filter vfs,$(USEMODULE)))
USEMODULE += posix_headers
ifeq (native, $(BOARD))
Expand Down
6 changes: 6 additions & 0 deletions sys/include/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,9 @@ int vfs_open(const char *name, int flags, mode_t mode);
*
* @return number of bytes read on success
* @return <0 on error
*
* For simple cases of only a single read from a file, the @ref
* vfs_file_to_buffer function can be used.
*/
ssize_t vfs_read(int fd, void *dest, size_t count);

Expand All @@ -806,6 +809,9 @@ ssize_t vfs_read(int fd, void *dest, size_t count);
*
* @return number of bytes written on success
* @return <0 on error
*
* For simple cases of only a single write to a file, the @ref
* vfs_file_from_buffer function can be used.
*/
ssize_t vfs_write(int fd, const void *src, size_t count);

Expand Down
59 changes: 59 additions & 0 deletions sys/include/vfs_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 ML!PA Consulting GmbH
*
* 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.
*/

/**
* @defgroup sys_vfs_util VFS helper functions
* @ingroup sys_vfs
Copy link
Member

Choose a reason for hiding this comment

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

While this is the right place from the module point of view, it's hard to discover. Maybe add a pointer to the vfs_read doc saying that "To read a complete file into a buffer, see also @ref vfs_file_to_buffer", or merely a "@see vfs_file_to_buffer".

* @{
*
* @file
* @brief VFS helper functions
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*/

#ifndef VFS_UTIL_H
#define VFS_UTIL_H

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Writes the content of a buffer to a file
* If the file already exists, it will be overwritten.
*
* @param[in] file Destination file path
* @param[in] buf Source buffer
* @param[in] len Buffer size
*
* @return 0 on success
* @return negative error from @ref vfs_open, @ref vfs_write
*/
int vfs_file_from_buffer(const char *file, const void *buf, size_t len);

/**
* @brief Reads the content of a file to a buffer
*
* @param[in] file Source file path
* @param[out] buf Destination buffer
* @param[in] len Buffer size
*
* @return number of bytes read on success
* @return -ENOSPC if the file was read successfully but is larger than
* the provided buffer. Only the first @p len bytes were read.
Comment on lines +48 to +49
Copy link
Member

@chrysn chrysn May 3, 2022

Choose a reason for hiding this comment

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

If this assurance is made toward the user, do we need to check that no other cause of error produces -ENOSPC? (It might be easier to just consider that a regular error with no guarantees -- also because that'd allow the implementation to instead stat the file after opening and return early without actually reading, if anyone wants to optimize that later.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think no fs will generate this error in the read path, but I could add

if (res == -ENOSPC) {
    res = -ENOMEM;
}

Copy link
Member

Choose a reason for hiding this comment

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

Documenting at the file system API that ENOSP must not be returned by read functions would also have worked, but this is the more robust way.

* @return negative error from @ref vfs_open, @ref vfs_read
*/
int vfs_file_to_buffer(const char* file, void* buf, size_t len);

#ifdef __cplusplus
}
#endif

#endif /* VFS_UTIL_H */
/** @} */
1 change: 1 addition & 0 deletions sys/vfs_util/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
81 changes: 81 additions & 0 deletions sys/vfs_util/vfs_util.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2021 Benjamin Valentin
*
* 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_vfs_util
* @{
* @file
* @brief VFS layer helper functions
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/

#include <fcntl.h>
#include <string.h>
#include <errno.h>

#include "vfs.h"
#include "vfs_util.h"

#define ENABLE_DEBUG 0
#include "debug.h"

int vfs_file_from_buffer(const char *file, const void *buf, size_t len)
{
int res, fd = vfs_open(file, O_CREAT | O_TRUNC | O_WRONLY, 0644);

if (fd < 0) {
DEBUG("can't open %s for writing\n", file);
return fd;
}

res = vfs_write(fd, buf, len);
vfs_close(fd);

if (res) {
return res;
}

return 0;
}

int vfs_file_to_buffer(const char* file, void* buf, size_t len)
{
int res, fd = vfs_open(file, O_RDONLY, 0);

if (fd < 0) {
DEBUG("can't open %s for reading\n", file);
return fd;
}

res = vfs_read(fd, buf, len);

/* ENOSPC is used to signal truncation */
/* Just for future proofing - this error code is not returned by any fs in the read path. */
if (res == -ENOSPC) {
DEBUG("read returned -ENOSPC\n");
res = -ENOMEM;
}

if (res > 0) {
if (res < (int)len) {
/* fill remaining buffer with 0 */
memset((char *)buf + res, 0, len - res);
} else {
/* check if there are more bytes in the file */
char c;
if (vfs_read(fd, &c, sizeof(c)) > 0) {
res = -ENOSPC;
}
}
}

vfs_close(fd);

return res;
}