fs: ext2: File operations

Introduced functions:
  - read
  - write
  - seek
  - tell

Signed-off-by: Franciszek Zdobylak <fzdobylak@antmicro.com>
This commit is contained in:
Franciszek Zdobylak 2023-02-24 10:12:04 +01:00 committed by Anas Nashif
parent 7b7b334bc3
commit a87cc6c0b6
3 changed files with 193 additions and 0 deletions

View file

@ -549,6 +549,88 @@ static int64_t find_dir_entry(struct ext2_inode *inode, const char *name, size_t
return -EINVAL;
}
/* Inode operations --------------------------------------------------------- */
ssize_t ext2_inode_read(struct ext2_inode *inode, void *buf, uint32_t offset, size_t nbytes)
{
int rc = 0;
ssize_t read = 0;
uint32_t block_size = inode->i_fs->block_size;
while (read < nbytes && offset < inode->i_size) {
uint32_t block = offset / block_size;
uint32_t block_off = offset % block_size;
rc = ext2_fetch_inode_block(inode, block);
if (rc < 0) {
break;
}
uint32_t left_on_blk = block_size - block_off;
uint32_t left_in_file = inode->i_size - offset;
size_t to_read = MIN(nbytes, MIN(left_on_blk, left_in_file));
memcpy((uint8_t *)buf + read, inode_current_block_mem(inode) + block_off, to_read);
read += to_read;
offset += to_read;
}
if (rc < 0) {
return rc;
}
return read;
}
ssize_t ext2_inode_write(struct ext2_inode *inode, const void *buf, uint32_t offset, size_t nbytes)
{
int rc = 0;
ssize_t written = 0;
uint32_t block_size = inode->i_fs->block_size;
while (written < nbytes) {
uint32_t block = offset / block_size;
uint32_t block_off = offset % block_size;
LOG_DBG("inode:%d Write to block %d (offset: %d-%zd/%d)",
inode->i_id, block, offset, offset + nbytes, inode->i_size);
rc = ext2_fetch_inode_block(inode, block);
if (rc < 0) {
break;
}
size_t to_write = MIN(nbytes, block_size - block_off);
memcpy(inode_current_block_mem(inode) + block_off, (uint8_t *)buf + written,
to_write);
LOG_DBG("Written %zd bytes at offset %d in block i%d", to_write, block_off, block);
rc = ext2_commit_inode_block(inode);
if (rc < 0) {
break;
}
written += to_write;
}
if (rc < 0) {
return rc;
}
if (offset + written > inode->i_size) {
LOG_DBG("New inode size: %d -> %zd", inode->i_size, offset + written);
inode->i_size = offset + written;
rc = ext2_commit_inode(inode);
if (rc < 0) {
return rc;
}
}
return written;
}
int ext2_get_direntry(struct ext2_dir *dir, struct fs_dirent *ent)
{
if (dir->d_off >= dir->d_inode->i_size) {

View file

@ -156,6 +156,36 @@ struct ext2_lookup_args {
*/
int ext2_lookup_inode(struct ext2_data *fs, struct ext2_lookup_args *args);
/* Inode operations */
/**
* @brief Read from inode at given offset
*
* @param inode Inode
* @param buf Buffer to hold read data
* @param offset Offset in inode
* @param nbytes Number of bytes to read
*
* @retval >=0 number of bytes read on success
* @retval <0 error code
*/
ssize_t ext2_inode_read(struct ext2_inode *inode, void *buf, uint32_t offset,
size_t nbytes);
/**
* @brief Write to inode at given offset
*
* @param inode Inode
* @param buf Buffer with data to write
* @param offset Offset in inode
* @param nbytes Number of bytes to write
*
* @retval >=0 number of bytes read on success
* @retval <0 error code
*/
ssize_t ext2_inode_write(struct ext2_inode *inode, const void *buf,
uint32_t offset, size_t nbytes);
/* Directory operations */
/**

View file

@ -125,6 +125,83 @@ out:
return rc;
}
static ssize_t ext2_read(struct fs_file_t *filp, void *dest, size_t nbytes)
{
struct ext2_file *f = filp->filep;
if ((f->f_flags & FS_O_READ) == 0) {
return -EACCES;
}
ssize_t r = ext2_inode_read(f->f_inode, dest, f->f_off, nbytes);
if (r < 0) {
return r;
}
f->f_off += r;
return r;
}
static ssize_t ext2_write(struct fs_file_t *filp, const void *src, size_t nbytes)
{
struct ext2_file *f = filp->filep;
if ((f->f_flags & FS_O_WRITE) == 0) {
return -EACCES;
}
if (f->f_flags & FS_O_APPEND) {
f->f_off = f->f_inode->i_size;
}
ssize_t r = ext2_inode_write(f->f_inode, src, f->f_off, nbytes);
if (r < 0) {
return r;
}
f->f_off += r;
return r;
}
static int ext2_lseek(struct fs_file_t *filp, off_t off, int whence)
{
struct ext2_file *f = filp->filep;
uint32_t new_off = 0;
switch (whence) {
case FS_SEEK_SET:
new_off = off;
break;
case FS_SEEK_CUR:
new_off = f->f_off + off;
break;
case FS_SEEK_END:
new_off = f->f_inode->i_size + off;
break;
default:
return -EINVAL;
}
/* New offset not inside the file. */
if (new_off < 0 || new_off > f->f_inode->i_size) {
return -EINVAL;
}
f->f_off = new_off;
return 0;
}
static off_t ext2_tell(struct fs_file_t *filp)
{
struct ext2_file *f = filp->filep;
return f->f_off;
}
/* Directory operations */
static int ext2_mkdir(struct fs_mount_t *mountp, const char *name)
@ -375,6 +452,10 @@ static int ext2_statvfs(struct fs_mount_t *mountp, const char *path, struct fs_s
static const struct fs_file_system_t ext2_fs = {
.open = ext2_open,
.close = ext2_close,
.read = ext2_read,
.write = ext2_write,
.lseek = ext2_lseek,
.tell = ext2_tell,
.mkdir = ext2_mkdir,
.mount = ext2_mount,
.unmount = ext2_unmount,