* @brief Copy a file from a location to another * * Behaves similarly to std::filesystem::copy_file but with less copy options. * * @param From Source file location. * @param To Destination file location. * @param Options Copy options. * * @return True if the copy succeeded, false otherwise. */
| 183 | * @return True if the copy succeeded, false otherwise. |
| 184 | */ |
| 185 | inline bool CopyFile(const fextl::string& From, const fextl::string& To, CopyOptions Options = CopyOptions::NONE) { |
| 186 | const bool DestExists = Exists(To); |
| 187 | if (Options == CopyOptions::SKIP_EXISTING && DestExists) { |
| 188 | // If the destination file exists already and the skip existing flag is set then |
| 189 | // return true without error. |
| 190 | return true; |
| 191 | } |
| 192 | |
| 193 | if (Options == CopyOptions::OVERWRITE_EXISTING && DestExists) { |
| 194 | // If we are overwriting and the file exists then we want to use `sendfile` to overwrite |
| 195 | int SourceFD = open(From.c_str(), O_RDONLY | O_CLOEXEC); |
| 196 | if (SourceFD == -1) { |
| 197 | return false; |
| 198 | } |
| 199 | |
| 200 | int DestinationFD = open(To.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0200); |
| 201 | if (DestinationFD == -1) { |
| 202 | close(SourceFD); |
| 203 | return false; |
| 204 | } |
| 205 | |
| 206 | struct stat buf; |
| 207 | if (fstat(SourceFD, &buf) != 0) { |
| 208 | close(DestinationFD); |
| 209 | close(SourceFD); |
| 210 | return false; |
| 211 | } |
| 212 | |
| 213 | // Set the destination permissions to the original source permissions. |
| 214 | if (fchmod(DestinationFD, buf.st_mode) != 0) { |
| 215 | close(DestinationFD); |
| 216 | close(SourceFD); |
| 217 | return false; |
| 218 | } |
| 219 | bool Result = sendfile(DestinationFD, SourceFD, nullptr, buf.st_size) == buf.st_size; |
| 220 | close(DestinationFD); |
| 221 | close(SourceFD); |
| 222 | return Result; |
| 223 | } |
| 224 | |
| 225 | if (!DestExists) { |
| 226 | // If the destination doesn't exist then just use rename. |
| 227 | return rename(From.c_str(), To.c_str()) == 0; |
| 228 | } |
| 229 | |
| 230 | return false; |
| 231 | } |
| 232 | |
| 233 | inline fextl::string LexicallyNormal(const fextl::string& Path) { |
| 234 | const auto PathSize = Path.size(); |