| 697 | } |
| 698 | |
| 699 | QVariantList Backend::scanOrphans() |
| 700 | { |
| 701 | QVariantList results; |
| 702 | if (m_accountId.isEmpty()) return results; |
| 703 | |
| 704 | QString accountDir = m_storagePath + "/" + m_accountId; |
| 705 | QDir dir(accountDir); |
| 706 | if (!dir.exists()) return results; |
| 707 | |
| 708 | // Internal metadata files that are never orphans |
| 709 | static const QSet<QString> whitelist = { |
| 710 | ".cloudredirect/Playtime.bin", |
| 711 | ".cloudredirect/UserGameStats.bin", |
| 712 | "Playtime.bin", |
| 713 | "UserGameStats.bin", |
| 714 | }; |
| 715 | |
| 716 | QStringList appDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); |
| 717 | for (const auto &appIdStr : appDirs) { |
| 718 | bool ok; |
| 719 | uint appId = appIdStr.toUInt(&ok); |
| 720 | if (!ok || appId == 0) continue; |
| 721 | |
| 722 | QString appDir = accountDir + "/" + appIdStr; |
| 723 | |
| 724 | // Read file_tokens.dat to get referenced filenames |
| 725 | QSet<QString> referenced; |
| 726 | QFile tokensFile(appDir + "/file_tokens.dat"); |
| 727 | if (tokensFile.open(QIODevice::ReadOnly | QIODevice::Text)) { |
| 728 | QTextStream in(&tokensFile); |
| 729 | while (!in.atEnd()) { |
| 730 | QString line = in.readLine(); |
| 731 | int tabIdx = line.indexOf('\t'); |
| 732 | if (tabIdx > 0) { |
| 733 | referenced.insert(line.left(tabIdx)); |
| 734 | } |
| 735 | } |
| 736 | tokensFile.close(); |
| 737 | } |
| 738 | |
| 739 | // List actual blob files |
| 740 | QString blobDir = appDir + "/blobs"; |
| 741 | QDir blobQDir(blobDir); |
| 742 | if (!blobQDir.exists()) continue; |
| 743 | |
| 744 | QStringList blobFiles = blobQDir.entryList(QDir::Files); |
| 745 | QStringList orphans; |
| 746 | qint64 orphanSize = 0; |
| 747 | |
| 748 | for (const auto &blob : blobFiles) { |
| 749 | if (whitelist.contains(blob)) continue; |
| 750 | if (!referenced.contains(blob)) { |
| 751 | orphans.append(blob); |
| 752 | QFileInfo fi(blobDir + "/" + blob); |
| 753 | orphanSize += fi.size(); |
| 754 | } |
| 755 | } |
| 756 | |