// fiko_updater.exe — FikoYT güncelleme kurulum yardımcısı (Dalga 3). // Çalışan ana uygulama kilitli exe/dll'lerini değiştiremez (Windows dosya kilidi) → // ayrı süreç şart. Akış: // 1) Ana uygulamanın (--pid) kapanmasını bekle (kilitler bırakılsın). // 2) Paketi (--zip) kurulum dizinine (--hedef) aç; her dosyayı ÖNCE yedekle (rollback). // 3) Başarısızsa yedekten geri yükle (rollback). Başarılıysa uygulamayı (--exe) başlat. // Kullanım: fiko_updater.exe --zip --hedef --pid --exe #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include "miniz.h" namespace { std::string arg(int argc, char** argv, const char* anahtar) { for (int i = 1; i + 1 < argc; ++i) if (std::strcmp(argv[i], anahtar) == 0) return argv[i + 1]; return ""; } bool dosyaVar(const std::string& yol) { const DWORD a = GetFileAttributesA(yol.c_str()); return a != INVALID_FILE_ATTRIBUTES && !(a & FILE_ATTRIBUTE_DIRECTORY); } // mkdir -p (ters eğik çizgi ayraçlı). Ara dizinleri sırayla kurar. void dizinKur(const std::string& yol) { std::string kismi; for (size_t i = 0; i < yol.size(); ++i) { kismi.push_back(yol[i]); if (yol[i] == '\\' || yol[i] == '/') CreateDirectoryA(kismi.c_str(), nullptr); } CreateDirectoryA(yol.c_str(), nullptr); } // Bir dosya yolunun üst dizinini kur. void ustDizinKur(const std::string& dosyaYolu) { const size_t k = dosyaYolu.find_last_of("\\/"); if (k != std::string::npos) dizinKur(dosyaYolu.substr(0, k)); } std::string birlestir(const std::string& dizin, std::string ad) { for (char& c : ad) if (c == '/') c = '\\'; return dizin + "\\" + ad; } } // namespace int main(int argc, char** argv) { const std::string zip = arg(argc, argv, "--zip"); const std::string hedef = arg(argc, argv, "--hedef"); const std::string pidS = arg(argc, argv, "--pid"); const std::string exe = arg(argc, argv, "--exe"); if (zip.empty() || hedef.empty() || !dosyaVar(zip)) { std::fprintf(stderr, "fiko_updater: eksik/gecersiz arguman\n"); return 2; } std::printf("FikoYT guncelleme kuruluyor...\n"); // 1) Ana uygulamanın kapanmasını bekle (dosya kilitleri bırakılsın). if (!pidS.empty()) { const DWORD pid = (DWORD)std::strtoul(pidS.c_str(), nullptr, 10); if (HANDLE hp = OpenProcess(SYNCHRONIZE, FALSE, pid)) { WaitForSingleObject(hp, 30000); // en fazla 30 sn CloseHandle(hp); } } Sleep(400); // kilit bırakma payı // 2) Paketi aç — her dosyayı önce yedekle (rollback için). const std::string yedekDir = hedef + "\\_guncelleme_yedek"; dizinKur(yedekDir); std::vector> yedekler; // (hedef, yedek) std::vector yeniler; // yeni oluşturulanlar (rollback=sil) mz_zip_archive z; std::memset(&z, 0, sizeof(z)); if (!mz_zip_reader_init_file(&z, zip.c_str(), 0)) { std::fprintf(stderr, "fiko_updater: zip acilamadi\n"); return 3; } bool ok = true; const mz_uint n = mz_zip_reader_get_num_files(&z); for (mz_uint i = 0; i < n && ok; ++i) { mz_zip_archive_file_stat st; if (!mz_zip_reader_file_stat(&z, i, &st)) { ok = false; break; } if (mz_zip_reader_is_file_a_directory(&z, i)) { dizinKur(birlestir(hedef, st.m_filename)); continue; } // Kendini (updater) kilitliyken değiştiremez → atla (bir sonraki güncellemede gelir). const char* taban = std::strrchr(st.m_filename, '/'); taban = taban ? taban + 1 : st.m_filename; if (_stricmp(taban, "fiko_updater.exe") == 0) continue; const std::string t = birlestir(hedef, st.m_filename); ustDizinKur(t); if (dosyaVar(t)) { const std::string yb = birlestir(yedekDir, st.m_filename); ustDizinKur(yb); if (CopyFileA(t.c_str(), yb.c_str(), FALSE)) yedekler.push_back({t, yb}); } else { yeniler.push_back(t); } if (!mz_zip_reader_extract_to_file(&z, i, t.c_str(), 0)) { std::fprintf(stderr, "fiko_updater: cikarma hatasi: %s\n", st.m_filename); ok = false; } } mz_zip_reader_end(&z); if (!ok) { // 3a) ROLLBACK — yedekleri geri yükle + yeni dosyaları sil. std::printf("Hata — geri aliniyor (rollback)...\n"); for (auto& [t, yb] : yedekler) CopyFileA(yb.c_str(), t.c_str(), FALSE); for (auto& yeni : yeniler) DeleteFileA(yeni.c_str()); } else { std::printf("Guncelleme tamam.\n"); } // Yedek dizinini temizle (başarı: gerekmiyor; hata: geri yüklendi). { std::string ftDizin = yedekDir; ftDizin.push_back('\0'); SHFILEOPSTRUCTA op; std::memset(&op, 0, sizeof(op)); op.wFunc = FO_DELETE; op.pFrom = ftDizin.c_str(); op.fFlags = FOF_NO_UI | FOF_SILENT | FOF_NOCONFIRMATION; SHFileOperationA(&op); } // 4) Uygulamayı yeniden başlat. if (!exe.empty() && dosyaVar(exe)) { STARTUPINFOA si; std::memset(&si, 0, sizeof(si)); si.cb = sizeof(si); PROCESS_INFORMATION pi; std::memset(&pi, 0, sizeof(pi)); std::string cmd = "\"" + exe + "\""; std::vector cmdBuf(cmd.begin(), cmd.end()); cmdBuf.push_back('\0'); const std::string calismaDizin = hedef; if (CreateProcessA(exe.c_str(), cmdBuf.data(), nullptr, nullptr, FALSE, 0, nullptr, calismaDizin.c_str(), &si, &pi)) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } } return ok ? 0 : 4; }