TODO: Test this with non-AT_FDCWD values.
| 975 | |
| 976 | // TODO: Test this with non-AT_FDCWD values. |
| 977 | int __syscall_renameat(int olddirfd, |
| 978 | const char* oldpath, |
| 979 | int newdirfd, |
| 980 | const char* newpath) { |
| 981 | // Rename is the only syscall that needs to (or is allowed to) acquire locks |
| 982 | // on two directories at once. It requires locks on both the old and new |
| 983 | // parent directories to ensure that the moved file can be atomically removed |
| 984 | // from the old directory and added to the new directory without something |
| 985 | // changing that would prevent the move. |
| 986 | // |
| 987 | // To prevent deadlock in the case of simultaneous renames, serialize renames |
| 988 | // with an additional global lock. |
| 989 | static std::mutex renameMutex; |
| 990 | std::lock_guard<std::mutex> renameLock(renameMutex); |
| 991 | |
| 992 | // Get the old directory. |
| 993 | auto parsedOld = path::parseParent(oldpath, olddirfd); |
| 994 | if (auto err = parsedOld.getError()) { |
| 995 | return err; |
| 996 | } |
| 997 | auto& [oldParent, oldFileNameView] = parsedOld.getParentChild(); |
| 998 | std::string oldFileName(oldFileNameView); |
| 999 | |
| 1000 | // Get the new directory. |
| 1001 | auto parsedNew = path::parseParent(newpath, newdirfd); |
| 1002 | if (auto err = parsedNew.getError()) { |
| 1003 | return err; |
| 1004 | } |
| 1005 | auto& [newParent, newFileNameView] = parsedNew.getParentChild(); |
| 1006 | std::string newFileName(newFileNameView); |
| 1007 | |
| 1008 | if (newFileNameView.size() > WASMFS_NAME_MAX) { |
| 1009 | return -ENAMETOOLONG; |
| 1010 | } |
| 1011 | |
| 1012 | // Lock both directories. |
| 1013 | auto lockedOldParent = oldParent->locked(); |
| 1014 | auto lockedNewParent = newParent->locked(); |
| 1015 | |
| 1016 | // Get the source and destination files. |
| 1017 | auto oldFile = lockedOldParent.getChild(oldFileName); |
| 1018 | auto newFile = lockedNewParent.getChild(newFileName); |
| 1019 | |
| 1020 | if (!oldFile) { |
| 1021 | return -ENOENT; |
| 1022 | } |
| 1023 | |
| 1024 | // If the source and destination are the same, do nothing. |
| 1025 | if (oldFile == newFile) { |
| 1026 | return 0; |
| 1027 | } |
| 1028 | |
| 1029 | // Never allow renaming or overwriting the root. |
| 1030 | auto root = wasmFS.getRootDirectory(); |
| 1031 | if (oldFile == root || newFile == root) { |
| 1032 | return -EBUSY; |
| 1033 | } |
| 1034 |
no test coverage detected