fs/unionfs: Support fchstat and chstat callback

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao 2021-08-10 14:03:00 +08:00 committed by Gustavo Henrique Nihei
parent 9d79f82e24
commit 9d96c54b1b

View File

@ -121,6 +121,9 @@ static int unionfs_tryrename(FAR struct inode *mountpt,
static int unionfs_trystat(FAR struct inode *inode,
FAR const char *relpath, FAR const char *prefix,
FAR struct stat *buf);
static int unionfs_trychstat(FAR struct inode *inode,
FAR const char *relpath, FAR const char *prefix,
FAR const struct stat *buf, int flags);
static int unionfs_trystatdir(FAR struct inode *inode,
FAR const char *relpath, FAR const char *prefix);
static int unionfs_trystatfile(FAR struct inode *inode,
@ -149,6 +152,8 @@ static int unionfs_dup(FAR const struct file *oldp,
FAR struct file *newp);
static int unionfs_fstat(FAR const struct file *filep,
FAR struct stat *buf);
static int unionfs_fchstat(FAR const struct file *filep,
FAR const struct stat *buf, int flags);
static int unionfs_truncate(FAR struct file *filep, off_t length);
/* Operations on directories */
@ -181,6 +186,9 @@ static int unionfs_rename(FAR struct inode *mountpt,
FAR const char *oldrelpath, FAR const char *newrelpath);
static int unionfs_stat(FAR struct inode *mountpt,
FAR const char *relpath, FAR struct stat *buf);
static int unionfs_chstat(FAR struct inode *mountpt,
FAR const char *relpath,
FAR const struct stat *buf, int flags);
/* Initialization */
@ -211,7 +219,7 @@ const struct mountpt_operations unionfs_operations =
unionfs_sync, /* sync */
unionfs_dup, /* dup */
unionfs_fstat, /* fstat */
NULL, /* fchstat */
unionfs_fchstat, /* fchstat */
unionfs_truncate, /* truncate */
unionfs_opendir, /* opendir */
@ -228,7 +236,7 @@ const struct mountpt_operations unionfs_operations =
unionfs_rmdir, /* rmdir */
unionfs_rename, /* rename */
unionfs_stat, /* stat */
NULL /* chstat */
unionfs_chstat /* chstat */
};
/****************************************************************************
@ -562,6 +570,38 @@ static int unionfs_trystat(FAR struct inode *inode, FAR const char *relpath,
return ops->stat(inode, trypath, buf);
}
/****************************************************************************
* Name: unionfs_trychstat
****************************************************************************/
static int unionfs_trychstat(FAR struct inode *inode,
FAR const char *relpath, FAR const char *prefix,
FAR const struct stat *buf, int flags)
{
FAR const struct mountpt_operations *ops;
FAR const char *trypath;
/* Is this path valid on this file system? */
trypath = unionfs_offsetpath(relpath, prefix);
if (trypath == NULL)
{
/* No.. return -ENOENT */
return -ENOENT;
}
/* Yes.. Try to change the status */
ops = inode->u.i_mops;
if (!ops->chstat)
{
return -ENOSYS;
}
return ops->chstat(inode, trypath, buf, flags);
}
/****************************************************************************
* Name: unionfs_trystatdir
****************************************************************************/
@ -1285,6 +1325,45 @@ static int unionfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
return ops->fstat ? ops->fstat(&uf->uf_file, buf) : -EPERM;
}
/****************************************************************************
* Name: unionfs_fchstat
*
* Description:
* Change information about an open file associated with the file
* descriptor 'filep'.
*
****************************************************************************/
static int unionfs_fchstat(FAR const struct file *filep,
FAR const struct stat *buf, int flags)
{
FAR struct unionfs_inode_s *ui;
FAR struct unionfs_file_s *uf;
FAR struct unionfs_mountpt_s *um;
FAR const struct mountpt_operations *ops;
finfo("filep=%p buf=%p\n", filep, buf);
/* Recover the open file data from the struct file instance */
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
ui = (FAR struct unionfs_inode_s *)filep->f_inode->i_private;
DEBUGASSERT(ui != NULL && filep->f_priv != NULL);
uf = (FAR struct unionfs_file_s *)filep->f_priv;
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
um = &ui->ui_fs[uf->uf_ndx];
DEBUGASSERT(um != NULL && um->um_node != NULL &&
um->um_node->u.i_mops != NULL);
ops = um->um_node->u.i_mops;
/* Perform the lower level change operation */
return ops->fchstat ? ops->fchstat(&uf->uf_file, buf, flags) : -EPERM;
}
/****************************************************************************
* Name: unionfs_truncate
*
@ -2441,6 +2520,50 @@ static int unionfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
return ret;
}
/****************************************************************************
* Name: unionfs_chstat
****************************************************************************/
static int unionfs_chstat(FAR struct inode *mountpt, FAR const char *relpath,
FAR const struct stat *buf, int flags)
{
FAR struct unionfs_inode_s *ui;
FAR struct unionfs_mountpt_s *um;
int ret;
finfo("relpath: %s\n", relpath);
/* Recover the union file system data from the struct inode instance */
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL &&
relpath != NULL);
ui = (FAR struct unionfs_inode_s *)mountpt->i_private;
/* chstat this path on file system 1 */
um = &ui->ui_fs[0];
ret = unionfs_trychstat(um->um_node, relpath, um->um_prefix, buf, flags);
if (ret >= 0)
{
/* Return on the first success. The first instance of the file will
* shadow the second anyway.
*/
return OK;
}
/* chstat failed on the file system 1. Try again on file system 2. */
um = &ui->ui_fs[1];
ret = unionfs_trychstat(um->um_node, relpath, um->um_prefix, buf, flags);
if (ret >= 0)
{
return OK;
}
return ret;
}
/****************************************************************************
* Name: unionfs_getmount
****************************************************************************/