TODO: consider moving this to be `Backend::move` to avoid asymmetry between the source and destination directories and/or taking `Directory::Handle` arguments to prove that the directories have already been locked.
| 138 | // the source and destination directories and/or taking `Directory::Handle` |
| 139 | // arguments to prove that the directories have already been locked. |
| 140 | int Directory::Handle::insertMove(const std::string& name, |
| 141 | std::shared_ptr<File> file) { |
| 142 | // Cannot insert into an unlinked directory. |
| 143 | if (!getParent()) { |
| 144 | return -EPERM; |
| 145 | } |
| 146 | |
| 147 | // Look up the file in its old parent's cache. |
| 148 | auto oldParent = file->locked().getParent(); |
| 149 | auto& oldCache = oldParent->dcache; |
| 150 | auto oldIt = std::find_if(oldCache.begin(), oldCache.end(), [&](auto& kv) { |
| 151 | return kv.second.file == file; |
| 152 | }); |
| 153 | |
| 154 | // TODO: Handle moving mount points correctly by only updating caches without |
| 155 | // involving the backend. |
| 156 | |
| 157 | // Attempt the move. |
| 158 | if (auto err = getDir()->insertMove(name, file)) { |
| 159 | return err; |
| 160 | } |
| 161 | |
| 162 | if (oldIt != oldCache.end()) { |
| 163 | // Do the move and update the caches. |
| 164 | auto [oldName, entry] = *oldIt; |
| 165 | assert(oldName.size()); |
| 166 | // Update parent pointers and caches to reflect the successful move. |
| 167 | oldCache.erase(oldIt); |
| 168 | auto& newCache = getDir()->dcache; |
| 169 | auto [it, inserted] = newCache.insert({name, entry}); |
| 170 | if (!inserted) { |
| 171 | // Update and overwrite the overwritten file. |
| 172 | it->second.file->locked().setParent(nullptr); |
| 173 | it->second = entry; |
| 174 | } |
| 175 | } else { |
| 176 | // This backend doesn't use the dcache. |
| 177 | assert(getDir()->maintainsFileIdentity()); |
| 178 | } |
| 179 | |
| 180 | file->locked().setParent(getDir()); |
| 181 | |
| 182 | // TODO: Moving mount points probably shouldn't update the mtime. |
| 183 | oldParent->locked().updateMTime(); |
| 184 | updateMTime(); |
| 185 | |
| 186 | return 0; |
| 187 | } |
| 188 | |
| 189 | int Directory::Handle::removeChild(const std::string& name) { |
| 190 | auto& dcache = getDir()->dcache; |
no test coverage detected