| 248 | } |
| 249 | |
| 250 | WasiExpect<void> VINode::pathSymlink(std::string_view OldPath, |
| 251 | std::shared_ptr<VINode> New, |
| 252 | std::string_view NewPath) { |
| 253 | if (unlikely(!New)) { |
| 254 | return WasiUnexpect(__WASI_ERRNO_BADF); |
| 255 | } |
| 256 | if (!New->can(__WASI_RIGHTS_PATH_SYMLINK)) { |
| 257 | return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE); |
| 258 | } |
| 259 | // Resolve the new path without following its trailing component (an existing |
| 260 | // link must not be followed, so creating over it fails with EEXIST), and |
| 261 | // capture the link directory's depth below the fd. |
| 262 | uint32_t ParentDepth = 0; |
| 263 | EXPECTED_TRY(auto NewBuffer, |
| 264 | resolvePath(New, NewPath, static_cast<__wasi_lookupflags_t>(0), |
| 265 | static_cast<VFS::Flags>(0), 0, true, &ParentDepth)); |
| 266 | |
| 267 | // Reject relative targets that resolve outside the preopen root; store |
| 268 | // in-bounds targets as-is. |
| 269 | if (isSymlinkTargetEscaping(OldPath, ParentDepth)) { |
| 270 | return WasiUnexpect(__WASI_ERRNO_PERM); |
| 271 | } |
| 272 | return New->Node.pathSymlink(std::string(OldPath), std::string(NewPath)); |
| 273 | } |
| 274 | |
| 275 | WasiExpect<void> VINode::pathUnlinkFile(std::shared_ptr<VINode> Fd, |
| 276 | std::string_view Path) { |
no test coverage detected