Przeglądaj źródła

UI/updater: Delete files listed as removed in manifest

derrod 3 lat temu
rodzic
commit
9a5e094cb3
2 zmienionych plików z 104 dodań i 2 usunięć
  1. 2 2
      UI/win-update/updater/hash.cpp
  2. 102 0
      UI/win-update/updater/updater.cpp

+ 2 - 2
UI/win-update/updater/hash.cpp

@@ -59,8 +59,8 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash)
 
 	for (;;) {
 		DWORD read = 0;
-		if (!ReadFile(handle, &hashBuffer[0], hashBuffer.size(), &read,
-			      nullptr))
+		if (!ReadFile(handle, &hashBuffer[0], (DWORD)hashBuffer.size(),
+			      &read, nullptr))
 			return false;
 
 		if (!read)

+ 102 - 0
UI/win-update/updater/updater.cpp

@@ -171,6 +171,20 @@ try {
 	return false;
 }
 
+static void MyDeleteFile(const wstring &filename)
+{
+	/* Try straightforward delete first */
+	if (DeleteFile(filename.c_str()))
+		return;
+
+	DWORD err = GetLastError();
+	if (err == ERROR_FILE_NOT_FOUND)
+		return;
+
+	/* If all else fails, schedule the file to be deleted on reboot */
+	MoveFileEx(filename.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+}
+
 static bool IsSafeFilename(const wchar_t *path)
 {
 	const wchar_t *p = path;
@@ -326,13 +340,29 @@ struct update_t {
 	}
 };
 
+struct deletion_t {
+	wstring originalFilename;
+	wstring deleteMeFilename;
+
+	void UndoRename()
+	{
+		if (!deleteMeFilename.empty())
+			MoveFile(deleteMeFilename.c_str(),
+				 originalFilename.c_str());
+	}
+};
+
 static vector<update_t> updates;
+static vector<deletion_t> deletions;
 static mutex updateMutex;
 
 static inline void CleanupPartialUpdates()
 {
 	for (update_t &update : updates)
 		update.CleanPartialUpdate();
+
+	for (deletion_t &deletion : deletions)
+		deletion.UndoRename();
 }
 
 /* ----------------------------------------------------------------------- */
@@ -745,6 +775,67 @@ static bool AddPackageUpdateFiles(const Json &root, size_t idx,
 	return true;
 }
 
+static void AddPackageRemovedFiles(const Json &package)
+{
+	const Json &removed_files = package["removed_files"];
+	if (!removed_files.is_array())
+		return;
+
+	for (auto &item : removed_files.array_items()) {
+		if (!item.is_string())
+			continue;
+
+		wchar_t removedFileName[MAX_PATH];
+		if (!UTF8ToWideBuf(removedFileName,
+				   item.string_value().c_str()))
+			continue;
+
+		/* Ensure paths are safe, also check if file exists */
+		if (!IsSafeFilename(removedFileName))
+			continue;
+		/* Technically GetFileAttributes can fail for other reasons,
+		 * so double-check by also checking the last error */
+		if (GetFileAttributesW(removedFileName) ==
+			    INVALID_FILE_ATTRIBUTES &&
+		    GetLastError() == ERROR_FILE_NOT_FOUND)
+			continue;
+
+		deletion_t deletion;
+		deletion.originalFilename = removedFileName;
+
+		deletions.push_back(deletion);
+	}
+}
+
+static bool RenameRemovedFile(deletion_t &deletion)
+{
+	_TCHAR deleteMeName[MAX_PATH];
+	_TCHAR randomStr[MAX_PATH];
+
+	BYTE junk[40];
+	BYTE hash[BLAKE2_HASH_LENGTH];
+
+	CryptGenRandom(hProvider, sizeof(junk), junk);
+	blake2b(hash, sizeof(hash), junk, sizeof(junk), NULL, 0);
+	HashToString(hash, randomStr);
+	randomStr[8] = 0;
+
+	StringCbCopy(deleteMeName, sizeof(deleteMeName),
+		     deletion.originalFilename.c_str());
+
+	StringCbCat(deleteMeName, sizeof(deleteMeName), L".");
+	StringCbCat(deleteMeName, sizeof(deleteMeName), randomStr);
+	StringCbCat(deleteMeName, sizeof(deleteMeName), L".deleteme");
+
+	if (MoveFile(deletion.originalFilename.c_str(), deleteMeName)) {
+		/* Only set this if the file was successfully renamed */
+		deletion.deleteMeFilename = deleteMeName;
+		return true;
+	}
+
+	return false;
+}
+
 static void UpdateWithPatchIfAvailable(const char *name, const char *hash,
 				       const char *source, int size)
 {
@@ -1295,6 +1386,9 @@ static bool Update(wchar_t *cmdLine)
 			Status(L"Update failed: Failed to process update packages");
 			return false;
 		}
+
+		/* Add removed files to deletion queue (if any) */
+		AddPackageRemovedFiles(packages[i]);
 	}
 
 	SendDlgItemMessage(hwndMain, IDC_PROGRESS, PBM_SETMARQUEE, 0, 0);
@@ -1476,6 +1570,10 @@ static bool Update(wchar_t *cmdLine)
 		}
 	}
 
+	for (deletion_t &deletion : deletions)
+		if (!RenameRemovedFile(deletion))
+			return false;
+
 	/* ------------------------------------- *
 	 * Install virtual camera                */
 
@@ -1546,6 +1644,10 @@ static bool Update(wchar_t *cmdLine)
 			DeleteFile(update.tempPath.c_str());
 	}
 
+	/* Delete all removed files mentioned in the manifest */
+	for (deletion_t &deletion : deletions)
+		MyDeleteFile(deletion.deleteMeFilename);
+
 	SendDlgItemMessage(hwndMain, IDC_PROGRESS, PBM_SETPOS, 100, 0);
 
 	Status(L"Update complete.");