77#include < sys/stat.h>
88#include < unistd.h>
99#include < cstring>
10+ #include < ctime>
1011#include < vector>
1112#include < string>
1213
@@ -32,6 +33,82 @@ void CacheManager::cleanupStaleZips() {
3233 LOG_INFO (" CacheManager: cleaned up %d stale zip(s)" , removed);
3334}
3435
36+ void CacheManager::cleanupStalePartials () {
37+ std::string dir = Paths::cacheDir ();
38+ DIR * d = opendir (dir.c_str ());
39+ if (!d) return ;
40+
41+ int removed = 0 ;
42+ time_t now = time (nullptr );
43+ constexpr time_t kMaxAgeSec = 24 * 60 * 60 ; // 24h
44+
45+ struct dirent * e;
46+ while ((e = readdir (d)) != nullptr ) {
47+ std::string name = e->d_name ;
48+ if (name.size () < 8 ) continue ;
49+ if (name.substr (name.size () - 8 ) != " .partial" ) continue ;
50+ std::string path = dir + " /" + name;
51+ struct stat st;
52+ if (stat (path.c_str (), &st) != 0 ) continue ;
53+ if (now - st.st_mtime > kMaxAgeSec ) {
54+ if (remove (path.c_str ()) == 0 ) {
55+ LOG_INFO (" CacheManager: removed stale .partial: %s" , name.c_str ());
56+ removed++;
57+ }
58+ }
59+ }
60+ closedir (d);
61+ if (removed > 0 )
62+ LOG_INFO (" CacheManager: cleaned up %d stale partial(s)" , removed);
63+ }
64+
65+ void CacheManager::cleanupStaleStaging () {
66+ // 1) Delete every subdirectory of cache/staging.
67+ std::string staging = Paths::stagingDir ();
68+ DIR * d = opendir (staging.c_str ());
69+ if (d) {
70+ int removed = 0 ;
71+ struct dirent * e;
72+ while ((e = readdir (d)) != nullptr ) {
73+ std::string name = e->d_name ;
74+ if (name == " ." || name == " .." ) continue ;
75+ if (DownloadManager::rmrf (staging + " /" + name)) removed++;
76+ }
77+ closedir (d);
78+ if (removed > 0 )
79+ LOG_INFO (" CacheManager: cleared %d stale staging entr%s" ,
80+ removed, removed == 1 ? " y" : " ies" );
81+ }
82+
83+ // 2) Delete any "<modid>.old" folders in active sdcafiine paths
84+ // (leftover from a crashed atomic-rename swap).
85+ std::vector<std::string> bases = { Paths::sdcafiineBase (), Paths::disabledBase () };
86+ for (auto & base : bases) {
87+ DIR * td = opendir (base.c_str ());
88+ if (!td) continue ;
89+ struct dirent * te;
90+ while ((te = readdir (td)) != nullptr ) {
91+ std::string titleId = te->d_name ;
92+ if (titleId == " ." || titleId == " .." ) continue ;
93+ std::string titlePath = base + " /" + titleId;
94+ DIR * md = opendir (titlePath.c_str ());
95+ if (!md) continue ;
96+ struct dirent * me;
97+ while ((me = readdir (md)) != nullptr ) {
98+ std::string entry = me->d_name ;
99+ if (entry == " ." || entry == " .." ) continue ;
100+ if (entry.size () > 4 && entry.substr (entry.size () - 4 ) == " .old" ) {
101+ std::string oldPath = titlePath + " /" + entry;
102+ if (DownloadManager::rmrf (oldPath))
103+ LOG_INFO (" CacheManager: removed stale .old: %s" , oldPath.c_str ());
104+ }
105+ }
106+ closedir (md);
107+ }
108+ closedir (td);
109+ }
110+ }
111+
35112void CacheManager::cleanupCorruptMods () {
36113 // Check both active and disabled base dirs
37114 std::vector<std::string> bases = {
0 commit comments