fs_node_t* vfs_lookup(const char* path);
+/* K21: Lookup without following symlinks (for O_NOFOLLOW) */
+fs_node_t* vfs_lookup_nofollow(const char* path);
+
/* Lookup from the saved initrd root (immune to pivot_root). */
void vfs_set_initrd_root(fs_node_t* root);
fs_node_t* vfs_lookup_initrd(const char* path);
node->f_ops->close(node);
}
-static fs_node_t* vfs_lookup_depth(const char* path, int depth);
+static fs_node_t* vfs_lookup_depth(const char* path, int depth, int lookup_flags);
+
+#define LOOKUP_FOLLOW 0x01
+#define LOOKUP_NOFOLLOW 0x02
+
+/* K21: Export for use in syscall.c */
+fs_node_t* vfs_lookup_nofollow(const char* path) {
+ return vfs_lookup_depth(path, 0, LOOKUP_NOFOLLOW);
+}
fs_node_t* vfs_lookup(const char* path) {
- return vfs_lookup_depth(path, 0);
+ return vfs_lookup_depth(path, 0, LOOKUP_FOLLOW);
}
void vfs_set_initrd_root(fs_node_t* root) {
return cur;
}
-static fs_node_t* vfs_lookup_depth(const char* path, int depth) {
+static fs_node_t* vfs_lookup_depth(const char* path, int depth, int lookup_flags) {
if (!path) return NULL;
if (depth > 8) return NULL;
cur = fn_finddir(cur, part);
if (!cur) return NULL;
+ /* K21: Only follow symlinks if LOOKUP_FOLLOW is set */
if (cur->flags == FS_SYMLINK && cur->symlink_target[0]) {
- cur = vfs_lookup_depth(cur->symlink_target, depth + 1);
+ if (lookup_flags & LOOKUP_NOFOLLOW) {
+ /* Don't follow the symlink - return it as-is */
+ return cur;
+ }
+ cur = vfs_lookup_depth(cur->symlink_target, depth + 1, lookup_flags);
if (!cur) return NULL;
}
}
return -EACCES;
}
- fs_node_t* node = vfs_lookup(path);
+ /* K21: Use vfs_lookup_nofollow when O_NOFOLLOW is set */
+ fs_node_t* node;
+ if (flags & 0x20000) { /* O_NOFOLLOW */
+ node = vfs_lookup_nofollow(path);
+ } else {
+ node = vfs_lookup(path);
+ }
if (!node && (flags & 0x40U) != 0U) {
/* O_CREAT: create file through VFS */
int rc = vfs_require_writable_path(path);