From fe9c0cc3445485221b12118c2f5e34cccde82105 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 28 Sep 2020 12:24:58 +0200 Subject: [server] Up the safety game even more: Don't delete if disjoint If non of the files in the known image list matches the list of files we find on the vmstore, don't delete anything. It's possible we mounted the wrong vmstore (test server vs. production system) and would totally ruin the day for someone. --- .../main/java/org/openslx/bwlp/sat/web/WebRpc.java | 53 ++++++++++++++-------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java index 1d5b27e7..3a6f39ad 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java @@ -7,13 +7,16 @@ import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import javax.security.auth.login.LoginException; @@ -88,14 +91,33 @@ public class WebRpc { if (known.isEmpty()) { return WebServer.internalServerError("SAFTY CHECK: Known image list empty, aborting"); } + AtomicInteger matches = new AtomicInteger(); try { // Consider only regular files, call checkFile for each one Files.find(Configuration.getVmStoreProdPath().toPath(), 8, (filePath, fileAttr) -> fileAttr.isRegularFile()) - .forEach((fileName) -> checkFile(fileName, orphanedFiles, baseLen, known, del)); + .forEach((fileName) -> checkFile(fileName, orphanedFiles, baseLen, known, matches)); } catch (IOException e) { return WebServer.internalServerError(e.toString()); } + if (del) { + for (Entry it : orphanedFiles.entrySet()) { + if (matches.get() == 0) { + // Don't delete anything if the set of known files and the set of files we actually + // found are disjoint + it.setValue(DeleteResult.SAFETY_ABORT); + continue; + } + Path filePath = Paths.get(baseDir + "/" + it.getKey()); + try { + Files.delete(filePath); + it.setValue(DeleteResult.DELETED); + } catch (Exception e) { + LOGGER.warn("Cannot delete " + filePath, e); + it.setValue(DeleteResult.ERROR); + } + } + } return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "application/json; charset=utf-8", Json.serialize(orphanedFiles)); } @@ -103,20 +125,23 @@ public class WebRpc { private static enum DeleteResult { EXISTS, DELETED, - ERROR; + ERROR, + SAFETY_ABORT; } /** - * Function called for each file found on the VMstore to determine if it's orphaned. + * Function called for each file found on the VMstore to determine if it's + * orphaned. * * @param filePath File to check * @param result Map to add the check result to - * @param baseLen length of the base path we need to strip from the absolute path + * @param baseLen length of the base path we need to strip from the absolute + * path * @param known list of known images from the db - * @param doDelete whether to delete all files we found to be orphaned + * @param matches counter for files that match a DB entry */ private static void checkFile(Path filePath, Map result, int baseLen, - Set known, boolean doDelete) { + Set known, AtomicInteger matches) { if (filePath.endsWith("dozmod.lock")) return; final String relativeFileName; @@ -135,18 +160,10 @@ public class WebRpc { } else { compareFileName = relativeFileName; } - if (!known.contains(compareFileName)) { - DeleteResult code = DeleteResult.EXISTS; - if (doDelete) { - try { - Files.delete(filePath); - code = DeleteResult.DELETED; - } catch (Exception e) { - LOGGER.warn("Cannot delete " + filePath, e); - code = DeleteResult.ERROR; - } - } - result.put(relativeFileName, code); + if (known.contains(compareFileName)) { + matches.incrementAndGet(); + } else { + result.put(relativeFileName, DeleteResult.EXISTS); } } -- cgit v1.2.3-55-g7522