Skip to content

Commit fa3a4a9

Browse files
Zfeather914yukangzhi
authored andcommitted
fs/vfs: add lstat interface to mountpt_operations
Add an lstat method to mountpt_operations so that mounted file systems can report link metadata without dereferencing symbolic links. In mountptrename() and stat_recursive(), prefer lstat() over stat() when it is available so that rename() and the non-following stat path operate on the link itself rather than its target, matching POSIX semantics. Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
1 parent 0158cb1 commit fa3a4a9

3 files changed

Lines changed: 47 additions & 10 deletions

File tree

fs/vfs/fs_rename.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -361,20 +361,48 @@ static int mountptrename(FAR const char *oldpath, FAR struct inode *oldinode,
361361
* then the rename should fail with the error ENOTEMPTY.
362362
*/
363363

364+
#ifdef CONFIG_FS_LINKS
365+
if (oldinode->u.i_mops->lstat != NULL || oldinode->u.i_mops->stat != NULL)
366+
#else
364367
if (oldinode->u.i_mops->stat != NULL)
368+
#endif
365369
{
366370
struct stat oldbuf;
367371
struct stat newbuf;
368372

369-
ret = oldinode->u.i_mops->stat(oldinode, oldrelpath, &oldbuf);
373+
#ifdef CONFIG_FS_LINKS
374+
/* Use lstat if available to avoid dereferencing symlinks */
375+
376+
if (oldinode->u.i_mops->lstat)
377+
{
378+
ret = oldinode->u.i_mops->lstat(oldinode, oldrelpath, &oldbuf);
379+
}
380+
else
381+
#endif
382+
{
383+
ret = oldinode->u.i_mops->stat(oldinode, oldrelpath, &oldbuf);
384+
}
385+
370386
if (ret < 0)
371387
{
372388
goto errout_with_newinode;
373389
}
374390

375391
oldisdir = S_ISDIR(oldbuf.st_mode);
376392

377-
ret = oldinode->u.i_mops->stat(oldinode, newrelpath, &newbuf);
393+
#ifdef CONFIG_FS_LINKS
394+
/* Use lstat if available to avoid dereferencing symlinks */
395+
396+
if (oldinode->u.i_mops->lstat)
397+
{
398+
ret = oldinode->u.i_mops->lstat(oldinode, newrelpath, &newbuf);
399+
}
400+
else
401+
#endif
402+
{
403+
ret = oldinode->u.i_mops->stat(oldinode, newrelpath, &newbuf);
404+
}
405+
378406
if (ret >= 0)
379407
{
380408
newisdir = S_ISDIR(newbuf.st_mode);
@@ -425,9 +453,9 @@ static int mountptrename(FAR const char *oldpath, FAR struct inode *oldinode,
425453
* method should check that.
426454
*/
427455

428-
oldinode->u.i_mops->unlink(oldinode, newrelpath);
456+
oldinode->u.i_mops->unlink(oldinode, newrelpath);
429457
#ifdef CONFIG_FS_NOTIFY
430-
notify_unlink(newrelpath);
458+
notify_unlink(newrelpath);
431459
#endif
432460
}
433461
}
@@ -522,15 +550,13 @@ int rename(FAR const char *oldpath, FAR const char *newpath)
522550
}
523551
else
524552
#endif /* CONFIG_DISABLE_MOUNTPOINT */
525-
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
526553
{
554+
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
527555
ret = pseudorename(oldpath, oldinode, olddesc.parent, newpath);
528-
}
529556
#else
530-
{
531557
ret = -ENXIO;
532-
}
533558
#endif
559+
}
534560

535561
inode_release(oldinode);
536562

fs/vfs/fs_stat.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,17 @@ static int stat_recursive(FAR const char *path,
123123
* supports the stat() method
124124
*/
125125

126+
# ifdef CONFIG_FS_LINKS
127+
/* use lstat() if available to avoid following symlinks */
128+
129+
if (!resolve && inode->u.i_mops && inode->u.i_mops->lstat)
130+
{
131+
ret = inode->u.i_mops->lstat(inode, desc.relpath, buf);
132+
}
133+
else
134+
# endif
126135
if (inode->u.i_mops && inode->u.i_mops->stat)
127136
{
128-
/* Perform the stat() operation */
129-
130137
ret = inode->u.i_mops->stat(inode, desc.relpath, buf);
131138
}
132139
else
@@ -428,6 +435,7 @@ int inode_stat(FAR struct inode *inode, FAR struct stat *buf, int resolve)
428435
(inode->u.i_bops->geometry != NULL))
429436
{
430437
struct geometry geo;
438+
431439
if (inode->u.i_bops->geometry(inode, &geo) >= 0 &&
432440
geo.geo_available)
433441
{

include/nuttx/fs/fs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,9 @@ struct mountpt_operations
412412
CODE ssize_t (*readlink)(FAR struct inode *mountpt,
413413
FAR const char *relpath,
414414
FAR char *buf, size_t bufsize);
415+
CODE int (*lstat)(FAR struct inode *mountpt,
416+
FAR const char *relpath,
417+
FAR struct stat *buf);
415418
#endif
416419
};
417420
#endif /* CONFIG_DISABLE_MOUNTPOINT */

0 commit comments

Comments
 (0)