MCPcopy Create free account
hub / github.com/BernardoGiordano/Checkpoint / copyFile

Method copyFile

switch/source/io.cpp:237–381  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

235}
236
237Result io::copyFile(const std::string& srcPath, const std::string& dstPath, ProgressSink& sink, u64 commitWriteLimit, u64* bytesCopied, u32* crcOut)
238{
239 FILE* src = fopen(srcPath.c_str(), "rb");
240 if (src == NULL) {
241 Logging::error("Failed to open source file {} during copy with errno {}.", srcPath, errno);
242 return RES_COPY_FAILED;
243 }
244 fseek(src, 0, SEEK_END);
245 u64 sz = ftell(src);
246 rewind(src);
247
248 const bool toSaveDevice = dstPath.rfind("save:/", 0) == 0;
249
250 // Create the destination at its final size instead of letting it grow one
251 // write at a time. Every extending write on the save filesystem has to find
252 // and chain a free block, so an append-grown tree of tens of thousands of
253 // files both fragments and gets slower as the save fills.
254 bool preallocated = false;
255 if (toSaveDevice && sz > 0) {
256 const Result cr = fsdevCreateFile(dstPath.c_str(), (size_t)sz, 0);
257 if (R_SUCCEEDED(cr)) {
258 preallocated = true;
259 }
260 else {
261 Logging::debug("Preallocating {} at {} bytes failed with result 0x{:08X}; growing it by writes instead.", dstPath, sz, (u32)cr);
262 }
263 }
264
265 // "wb" truncates, which would throw the preallocation away: an already-sized
266 // file has to be opened for update instead.
267 FILE* dst = fopen(dstPath.c_str(), preallocated ? "r+b" : "wb");
268 if (dst == NULL) {
269 Logging::error("Failed to open destination file {} during copy with errno {}.", dstPath, errno);
270 fclose(src);
271 return RES_COPY_FAILED;
272 }
273
274 u8* buf = new u8[BUFFER_SIZE];
275 u64 offset = 0;
276 u32 crc = 0;
277 Result res = 0;
278
279 size_t slashpos = srcPath.rfind("/");
280 sink.startFile(srcPath.substr(slashpos + 1, srcPath.length() - slashpos - 1), sz);
281
282 // The save journal only holds `commitWriteLimit` bytes of uncommitted writes:
283 // a single file bigger than that must be committed partway through, or the
284 // commit at the end would overflow the journal and fail (#443, #297).
285 u64 journalPending = 0;
286
287 while (offset < sz) {
288 if (sink.cancelled()) {
289 break;
290 }
291
292 size_t count = fread((char*)buf, 1, BUFFER_SIZE, src);
293 if (count == 0) {
294 Logging::error("fread returned 0 for file {} at offset {}/{} with errno {}. Aborting copy.", srcPath, offset, sz, errno);

Callers

nothing calls this directly

Calls 7

updateCrcFunction · 0.70
errorFunction · 0.50
debugFunction · 0.50
startFileMethod · 0.45
cancelledMethod · 0.45
advanceBytesMethod · 0.45
finishFileMethod · 0.45

Tested by

no test coverage detected