This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new f76e63dbc36 fs/unionfs: fix open leak, file position, opendir error
and statfs
f76e63dbc36 is described below
commit f76e63dbc367519db16fcd47d71c4302353156ea
Author: v-liuchenxu3 <[email protected]>
AuthorDate: Thu Nov 12 01:13:11 2026 +0800
fs/unionfs: fix open leak, file position, opendir error and statfs
unionfs_open() leaked the file container when the path failed to open
on both file systems.
unionfs_seek(), unionfs_read() and unionfs_write() only moved the
lower file, but file_seek() returns filep->f_pos, so lseek() reported
a stale offset and pread() and pwrite() restored the wrong position.
Keep filep->f_pos in sync with the lower file.
unionfs_opendir() returned OK after freeing the directory when
strdup() failed. Return -ENOMEM instead.
unionfs_statfs() multiplied f_blocks into the block size ratio, which
inflated the combined block counts when the block sizes differ.
Also correct comments that named the wrong file system or operation.
Signed-off-by: v-liuchenxu3 <[email protected]>
Signed-off-by: jingfei <[email protected]>
---
fs/unionfs/fs_unionfs.c | 52 +++++++++++++++++++++++++++++++++++++------------
1 file changed, 40 insertions(+), 12 deletions(-)
diff --git a/fs/unionfs/fs_unionfs.c b/fs/unionfs/fs_unionfs.c
index d6072bd78f3..f5445d50e3f 100644
--- a/fs/unionfs/fs_unionfs.c
+++ b/fs/unionfs/fs_unionfs.c
@@ -912,7 +912,7 @@ static int unionfs_open(FAR struct file *filep, FAR const
char *relpath,
}
else
{
- /* Try to open the file on file system 1 */
+ /* Try to open the file on file system 2 */
um = &ui->ui_fs[1];
@@ -923,10 +923,11 @@ static int unionfs_open(FAR struct file *filep, FAR const
char *relpath,
mode);
if (ret < 0)
{
+ fs_heap_free(uf);
goto errout_with_lock;
}
- /* Successfully opened on file system 1 */
+ /* Successfully opened on file system 2 */
uf->uf_ndx = 1;
}
@@ -1021,6 +1022,7 @@ static ssize_t unionfs_read(FAR struct file *filep, FAR
char *buffer,
FAR struct unionfs_file_s *uf;
FAR struct unionfs_mountpt_s *um;
FAR const struct mountpt_operations *ops;
+ ssize_t ret;
finfo("buflen: %lu\n", (unsigned long)buflen);
@@ -1040,7 +1042,18 @@ static ssize_t unionfs_read(FAR struct file *filep, FAR
char *buffer,
/* Perform the lower level read operation */
- return ops->read ? ops->read(&uf->uf_file, buffer, buflen) : -EPERM;
+ if (ops->read == NULL)
+ {
+ return -EPERM;
+ }
+
+ ret = ops->read(&uf->uf_file, buffer, buflen);
+ if (ret > 0)
+ {
+ filep->f_pos = uf->uf_file.f_pos;
+ }
+
+ return ret;
}
/****************************************************************************
@@ -1054,6 +1067,7 @@ static ssize_t unionfs_write(FAR struct file *filep, FAR
const char *buffer,
FAR struct unionfs_file_s *uf;
FAR struct unionfs_mountpt_s *um;
FAR const struct mountpt_operations *ops;
+ ssize_t ret;
finfo("buflen: %lu\n", (unsigned long)buflen);
@@ -1073,7 +1087,18 @@ static ssize_t unionfs_write(FAR struct file *filep, FAR
const char *buffer,
/* Perform the lower level write operation */
- return ops->write ? ops->write(&uf->uf_file, buffer, buflen) : -EPERM;
+ if (ops->write == NULL)
+ {
+ return -EPERM;
+ }
+
+ ret = ops->write(&uf->uf_file, buffer, buflen);
+ if (ret > 0)
+ {
+ filep->f_pos = uf->uf_file.f_pos;
+ }
+
+ return ret;
}
/****************************************************************************
@@ -1108,6 +1133,10 @@ static off_t unionfs_seek(FAR struct file *filep, off_t
offset, int whence)
if (ops->seek != NULL)
{
offset = ops->seek(&uf->uf_file, offset, whence);
+ if (offset >= 0)
+ {
+ filep->f_pos = offset;
+ }
}
else
{
@@ -1261,7 +1290,7 @@ static int unionfs_dup(FAR const struct file *oldp, FAR
struct file *newp)
memcpy(newpriv, oldpriv, sizeof(struct unionfs_file_s));
newpriv->uf_file.f_priv = NULL;
- /* Then perform the lower lowel dup operation */
+ /* Then perform the lower level dup operation */
ret = OK;
if (ops->dup != NULL)
@@ -1314,7 +1343,7 @@ static int unionfs_fstat(FAR const struct file *filep,
FAR struct stat *buf)
um->um_node->u.i_mops != NULL);
ops = um->um_node->u.i_mops;
- /* Perform the lower level write operation */
+ /* Perform the lower level fstat operation */
return ops->fstat ? ops->fstat(&uf->uf_file, buf) : -EPERM;
}
@@ -1388,7 +1417,7 @@ static int unionfs_truncate(FAR struct file *filep, off_t
length)
um->um_node->u.i_mops != NULL);
ops = um->um_node->u.i_mops;
- /* Perform the lower level write operation */
+ /* Perform the lower level truncate operation */
return ops->truncate ? ops->truncate(&uf->uf_file, length) : -EPERM;
}
@@ -1443,6 +1472,7 @@ static int unionfs_opendir(FAR struct inode *mountpt,
udir->fu_relpath = fs_heap_strdup(relpath);
if (!udir->fu_relpath)
{
+ ret = -ENOMEM;
goto errout_with_lock;
}
}
@@ -2128,16 +2158,14 @@ static int unionfs_statfs(FAR struct inode *mountpt,
FAR struct statfs *buf)
{
if (buf1.f_bsize < buf2.f_bsize)
{
- tmp = (((uint64_t)buf2.f_blocks *
- (uint64_t)buf2.f_bsize) << 16);
+ tmp = (uint64_t)buf2.f_bsize << 16;
ratiob16 = (uint32_t)(tmp / buf1.f_bsize);
adj = &buf2;
}
else
{
buf->f_bsize = buf2.f_bsize;
- tmp = (((uint64_t)buf1.f_blocks *
- (uint64_t)buf1.f_bsize) << 16);
+ tmp = (uint64_t)buf1.f_bsize << 16;
ratiob16 = (uint32_t)(tmp / buf2.f_bsize);
adj = &buf1;
}
@@ -2211,7 +2239,7 @@ static int unionfs_unlink(FAR struct inode *mountpt,
ret = unionfs_trystat(um->um_node, relpath, um->um_prefix, &buf);
if (ret >= 0)
{
- /* Yes.. Try to unlink the file on file system 1. This would fail
+ /* Yes.. Try to unlink the file on file system 2. This would fail
* with -ENOSYS if file system 2 is a read-only only file system or
* -EISDIR if the path is not a file.
* */