Root cause: _inode_search() built the absolute form of a relative
path with snprintf(buf, PATH_MAX, "%s/%s", cwd, path), silently
truncating it when cwd + "/" + path exceeded PATH_MAX. The truncated
buffer was then handed to _inode_canonicalize(), which collapsed
".." segments against the wrong cut-off suffix. A valid relative
path of PATH_MAX-1 bytes (legal per pathconf(_PC_PATH_MAX)) could
thus collapse onto a directory and open() returned EISDIR instead
of resolving the file.
Fix: size the temp buffer to hold the full uncanonicalized
"<cwd>/<path>" form so canonicalization sees the complete path.
lib_get_tempbuffer falls back to a malloc'd buffer when the size
exceeds PATH_MAX (CONFIG_LIBC_TEMPBUFFER_MALLOC). The existing
PATH_MAX check in _inode_canonicalize() still rejects any
canonicalized result that is too long, so ENAMETOOLONG semantics
are preserved.
Signed-off-by: dengwenqi <dengwenqi@xiaomi.com>
Since _inode_canonicalize() now resolves all "." and ".." segments
in the common VFS layer before inode search, the relpath passed to
each filesystem will never contain ".." segments. Remove the
now-dead ".." handling code from individual filesystem layers and
the inode search internals.
Files modified (redundant ".." path resolution removed):
- fs/hostfs/hostfs.c: remove depth-tracking escape check in
hostfs_mkpath(), simplify to direct path concatenation.
- fs/rpmsgfs/rpmsgfs.c: same as hostfs, remove depth-tracking in
rpmsgfs_mkpath().
- fs/smartfs/smartfs_utils.c: remove "." and ".." segment checks
in smartfs_finddirentry(), de-indent the remaining search logic.
- fs/inode/fs_inodesearch.c: remove _inode_isdotdot() function,
simplify _compute_path_depth() to only count forward segments,
remove dead else-if branch in _inode_search().
Files NOT modified (and why):
- fs/littlefs/littlefs/lfs.c: third-party upstream library (git
submodule), must not be modified locally.
- fs/fatfs/fatfs/source/ff.c: third-party upstream library.
- fs/lwext4/lwext4/src/ext4*.c: third-party upstream library.
- fs/cromfs/fs_cromfs.c: handles "." and ".." as directory entries
(structural, not path resolution), so its code stays.
- fs/vfs/fs_symlink.c: constructs relative paths containing ".."
(writes, not parses relpath).
Signed-off-by: yukangzhi <yukangzhi@xiaomi.com>
Add _inode_canonicalize() to remove '.' and '..' segments from the
absolute path before the inode tree traversal begins. This fixes the
case where paths containing '..' that resolve back to a mountpoint
root (e.g., /tmp/subdir/..) were not being handed to the filesystem.
Previously, _compute_path_depth() returned 0 for such paths, causing
the VFS to skip the mountpoint and attempt to find 'subdir' in the
pseudo filesystem -- which fails with ENOTDIR.
With canonicalization, /tmp/subdir/.. becomes /tmp before the search,
so the mountpoint is correctly matched. This fixes chdir('..'),
stat('../..'), opendir('../..'), and similar operations from within
mountpoint subdirectories.
The implementation uses an in-place two-pointer algorithm with no
additional stack allocation, safe for NuttX's small kernel stacks.
Signed-off-by: yukangzhi <yukangzhi@xiaomi.com>
The loop condition 'namelen <= NAME_MAX' allowed filenames of
NAME_MAX+1 characters to pass validation. When the filename segment
reached exactly NAME_MAX+1 chars and was at the end of the path
string, the loop exited due to *path == '\0' and returned OK instead
of -ENAMETOOLONG.
Fix by moving the NAME_MAX check inside the loop body with an
immediate return on violation. Also fix the post-loop return to
explicitly check pathlen >= PATH_MAX instead of relying on *path
which conflated the two exit conditions.
Before: creat() with 97-char filename (NAME_MAX=96) succeeded
After: creat() with 97-char filename correctly returns ENAMETOOLONG
Signed-off-by: yukangzhi <yukangzhi@xiaomi.com>
The _inode_checkpath function uses `namelen < NAME_MAX` to validate
path segment lengths. When a filename is exactly NAME_MAX characters
long and is followed by more path segments (e.g. /dir/), the loop
exits with namelen == NAME_MAX before processing the '/' separator,
causing a spurious ENAMETOOLONG error.
Per POSIX, NAME_MAX is the maximum number of bytes in a filename not
including the terminating null, so a filename of exactly NAME_MAX
characters is valid. Change the condition to `namelen <= NAME_MAX`
so the loop can process the trailing '/' separator and correctly
reset namelen for the next path segment.
Signed-off-by: wangxingxing <wangxingxing@xiaomi.com>
Add a helper _inode_checkpath() that validates the path before the
search: it returns -ENOENT for an empty path and -ENAMETOOLONG when any
single path component exceeds NAME_MAX or the whole path exceeds
PATH_MAX. inode_search() now runs this check first so that oversized
paths and file names are rejected with the correct POSIX error code.
Signed-off-by: guohao15 <guohao15@xiaomi.com>
Add support for resolving relative path components (in particular the
".." parent references) during the inode search. A helper
_compute_path_depth() computes the remaining path depth so that a mount
point is only treated as the terminal node when the depth is positive,
and "../" components walk back up to the parent inode.
Signed-off-by: zhaoxingyu1 <zhaoxingyu1@xiaomi.com>
Replace the fs_heap_asprintf()/fs_heap_free() based allocation of the
path buffer in the inode search with the lib_get_tempbuffer()/
lib_put_tempbuffer() pool. Fixed PATH_MAX sized temporary buffers avoid
per-call heap allocation and keep the buffer allocator consistent with
the rest of the path-resolution code.
Signed-off-by: zhaoxingyu1 <zhaoxingyu1@xiaomi.com>
While walking the path components, a non-final component must refer to a
directory. When descending into a child, verify the parent inode is a
pseudo directory; if it is not, stop the search and return -ENOTDIR as
required by POSIX for a path prefix that is not a directory.
Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
An empty pathname does not name any inode. Return -ENOENT early in
inode_search() when the path is an empty string, instead of continuing
into the search logic with a zero-length path.
Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
When resolving a symbolic link target, call the public inode_search()
instead of the internal _inode_search() so that the link target path is
first formatted (leading '/' handling and relative-path conversion)
before the lookup. This ensures link targets are resolved through the
same normalization path as ordinary lookups.
Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
The link support is no longer limited to the pseudo file system and now
covers both soft (symbolic) links and hard links across the VFS. Rename
the configuration option PSEUDOFS_SOFTLINKS to the more accurate FS_LINKS
and update all references in the source, headers, Kconfig, documentation
and board defconfigs accordingly.
This is a configuration rename; any out-of-tree defconfig that still
selects PSEUDOFS_SOFTLINKS must be updated to FS_LINKS.
Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
inode_nextname() already skipped a '.' segment mid-path (e.g. "./foo"),
but only checked for a '/' right after it -- a path ending in a bare
'.' (e.g. "/foo/.", or "." itself once AT_FDCWD resolution prepends
$PWD) fell through and was looked up as a literal child named ".",
which no real node is ever named, failing with ENOENT.
This broke every "operate on the current directory" idiom relative
paths rely on: bare `ls`, `stat .`, `cd .`, etc., all failed outright
even though the equivalent absolute path worked fine. Found while
testing the Toybox port's interactive REPL, but this is generic VFS
path resolution, not Toybox-specific.
Signed-off-by: Alan C. Assis <acassis@gmail.com>
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Most tools used for compliance and SBOM generation use SPDX identifiers
This change brings us a step closer to an easy SBOM generation.
Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>
In ./fs/inode directory, the variable name FAR struct inode *node is named inconsistently, with some using node and others using inode. To facilitate understanding, we will standardize the naming to FAR struct inode *inode.
Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
sched implementation not depends on macro abstraction, so revert below commit:
This reverts commit 4e62d0005a
This reverts commit 0f0c370520
This reverts commit ad0efd04ee
Signed-off-by: chao an <anchao@lixiang.com>
fix the problem that stat fails to use the relative path
An error will be reported if used in the following way:
stat("//./bin", &st);
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
* Simplify EINTR/ECANCEL error handling
1. Add semaphore uninterruptible wait function
2 .Replace semaphore wait loop with a single uninterruptible wait
3. Replace all sem_xxx to nxsem_xxx
* Unify the void cast usage
1. Remove void cast for function because many place ignore the returned value witout cast
2. Replace void cast for variable with UNUSED macro