Skip to content

Instantly share code, notes, and snippets.

@ekmillard
Created December 7, 2023 22:28
Show Gist options
  • Save ekmillard/9df5d5481b9b4154adcf2e97958c62a7 to your computer and use it in GitHub Desktop.
Save ekmillard/9df5d5481b9b4154adcf2e97958c62a7 to your computer and use it in GitHub Desktop.
package ps.eden.server.cache.editor.leanbow;
import ps.eden.server.ServerConstants;
import ps.eden.server.cache.editor.mgi.tools.rseditor.core.cache.*;
import ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer;
import ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.Whirlpool;
public class CacheRepair {
/**
* Wheter to generate missing filesystems.
*/
private boolean generateMissingFilesystems;
/**
* Whether to not remove missing folders.
*/
private boolean dontRemoveMissingFolders;
public static void main(String[] args) {
args = new String[] {"-x", ServerConstants.CACHE_530_DIR};
StringBuilder bldArgs = new StringBuilder();
for (int i = 0; i < args.length; i++) {
bldArgs.append(args[i]);
if ((i + 1) < args.length)
bldArgs.append(' ');
}
try {
new CacheRepair().command(bldArgs.toString());
} catch (Throwable t) {
if (t.getMessage().contains("startup"))
main(new String[0]); // output usage
else if (t.getMessage().contains("notfound"))
System.err.println("Couldn't find cache.");
else if (t.getMessage().contains("error")) {
System.err.println("Oops! An error occured:");
t.getCause().printStackTrace();
}
}
}
public Object command(String command) {
String path = null;
for (int offset = 0; offset < command.length();) {
if (command.charAt(offset) == '-') {
if ((offset + 1) >= command.length()) {
System.err.println("Bad option syntax, required -[option], found -[endofcommand]");
throw new RuntimeException("startup:badoption");
}
char option = command.charAt(++offset);
if (option == 'x')
generateMissingFilesystems = true;
else if (option == 'd')
dontRemoveMissingFolders = true;
else {
System.err.println("Unknown option: [-" + option + "]");
throw new RuntimeException("startup:badoption");
}
offset++;
} else if (command.charAt(offset) == ' ')
offset++;
else {
path = command.substring(offset);
break;
}
}
if (path == null)
throw new RuntimeException("notfound:");
try {
doRecover(path);
} catch (Throwable t) {
throw new RuntimeException("error:unexpected", t);
}
return null;
}
public void doRecover(String path) {
Cache cache = Cache.openCache(path);
int totalErrors = 0;
for (int i = 0; i < cache.getIndicesCount(); i++) {
if (i == 6 || i == 14 || i == 5 /* maps */)
continue;
System.err.println("Verifying information of:" + i);
FileSystem system;
try {
system = cache.getFilesSystem(i);
} catch (Throwable t) {
totalErrors++;
System.err.println("------------------------------");
System.err.println("Failed to load information");
if (generateMissingFilesystems) {
System.err.println("Trying to regenerate filesystem");
try {
byte[] pdata = Helper.encodeFITContainer(new byte[] { 5, 0, 0, 0 }, 0); // empty
// fs
// (protocol
// 5,
// props
// 0,
// folders
// count
// -
// 0)
cache.getInformationStore().put(i, new ByteBuffer(pdata), pdata.length);
system = cache.getFilesSystem(i);
system.setUseAutomaticVersionsIncremetor(false);
int count = cache.getFilesStore(i).getFileCount();
for (int file = 0; file < count; file++) {
ByteBuffer data = cache.getFilesStore(i).get(file);
if (data == null || !Helper.validFilesContainer(data)) {
if (data != null)
System.err.println("Failed to recover folder:" + file + ", because data appears corrupt.");
continue;
}
try {
ByteBuffer f = Helper.decodeFilesContainer(data);
system.addFolder(new Folder(file, -1, Helper.decodeVersion(data), new File[] { new File(0, -1, f) }));
System.err.println("Recovered folder:" + file);
} catch (Throwable ttt) {
System.err.println("Failed to recover folder:" + file);
}
}
System.err.println("Successfully regenerated filesystem");
} catch (Throwable tt) {
System.err.println("Failed to regenerate filesystem");
}
}
System.err.println("------------------------------");
continue;
}
system.setUseAutomaticVersionsIncremetor(false);
System.err.println("------------------------------");
System.err.println("Information loading sucessfull");
System.err.println("Folders count:" + system.getFolders().length);
System.err.println("Uses names:" + system.usesNames());
System.err.println("Uses whirlpool:" + system.usesWhirlpool());
System.err.println("Version:" + system.getVersion());
System.err.println("Verifying files of:" + i);
Folder[] folders = new Folder[system.getFolders().length];
System.arraycopy(system.getFolders(), 0, folders, 0, folders.length);
int errorsCount = 0;
for (int a = 0; a < folders.length; a++) {
Folder folder = folders[a];
ByteBuffer data = cache.getFilesStore(i).get(folder.getID());
if (data == null) {
System.err.println("Missing folder - " + folder.getID());
errorsCount++;
if (!dontRemoveMissingFolders) {
system.deleteFolder(folder);
System.err.println("Deleted folder " + folder.getID() + " entry from fs.");
}
continue;
}
if (Helper.decodeVersion(data) != (folder.getVersion() & 0xFFFF)) {
System.err.println("Folder " + folder.getID() + " has incorrect version:" + Helper.decodeVersion(data) + ", expected:" + (folder.getVersion() & 0xFFFF));
folder.setVersion(Helper.decodeVersion(data));
errorsCount++;
}
boolean recalc = false;
if (Helper.crc32(data, 0, data.getBuffer().length - 2) != folder.getCRC32()) {
System.err.println("Folder " + folder.getID() + " has incorrect crc:" + Helper.crc32(data, 0, data.getBuffer().length - 2) + ", expected:" + folder.getCRC32());
recalc = true;
errorsCount++;
}
if (system.usesWhirlpool()) {
byte[] digest = Whirlpool.whirlpool(data.getBuffer(), 0, data.getBuffer().length - 2);
for (int d = 0; d < 64; d++)
if (digest[d] != folder.getDigest()[d]) {
System.err.println("Folder " + folder.getID() + " has incorrect whirlpool digest.");
recalc = true;
errorsCount++;
break;
}
}
if (recalc)
folder.recalculate();
}
totalErrors += errorsCount;
System.err.println("Done verifying files, errors:" + errorsCount);
System.err.println("------------------------------");
}
cache.close();
System.err.println("Done, total errors count:" + totalErrors);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment