Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- ndisk_verify.lua
- -- Verifies which files in chunklocation.txt actually exist on nodes
- -- Reports recoverable vs broken files, optionally cleans up broken entries
- local modem = peripheral.find("modem")
- if not modem then error("No modem found") end
- modem.open(5)
- -- Load NDisk secret for authentication
- local NDISK_SECRET = nil
- if fs.exists(".ndisk_secret") then
- local f = fs.open(".ndisk_secret", "r")
- NDISK_SECRET = f.readAll()
- f.close()
- end
- local REQUEST_TIMEOUT = 2
- local LOG_FILE = "ndisk_verify_results.txt"
- local function generateRequestId()
- return os.getComputerID() .. "_" .. os.epoch("utc") .. "_" .. math.random(10000)
- end
- local function sendRequest(nodeId, request)
- request.targetNode = nodeId
- request.secret = NDISK_SECRET -- Include auth secret
- modem.transmit(5, 5, request)
- local timer = os.startTimer(REQUEST_TIMEOUT)
- while true do
- local event, p1, p2, p3, p4 = os.pullEvent()
- if event == "modem_message" and type(p4) == "table" and p4.id == request.id then
- return p4.response
- elseif event == "timer" and p1 == timer then
- return nil
- end
- end
- end
- local function main()
- term.clear()
- term.setCursorPos(1, 1)
- term.setTextColor(colors.cyan)
- print("========================================")
- print(" NDisk Verification Tool")
- print("========================================")
- term.setTextColor(colors.white)
- print("")
- if not fs.exists("chunklocation.txt") then
- print("ERROR: chunklocation.txt not found!")
- return
- end
- -- Parse chunklocation.txt
- print("Loading chunk map...")
- local chunkMap = {} -- path -> {chunkNum -> {primary, mirror}}
- local file = fs.open("chunklocation.txt", "r")
- for line in file.readLine do
- local parts = {}
- for part in line:gmatch("%S+") do
- table.insert(parts, part)
- end
- if #parts >= 3 then
- local filename = parts[1]
- local chunkMatch = parts[2]:match("chunk(%d+)")
- local chunkNum = chunkMatch and tonumber(chunkMatch) or nil
- local primaryId = tonumber(parts[3])
- local mirrorId = parts[4] and tonumber(parts[4]) or nil
- if filename and chunkNum and primaryId then
- chunkMap[filename] = chunkMap[filename] or {}
- chunkMap[filename][chunkNum] = {primary = primaryId, mirror = mirrorId}
- end
- end
- end
- file.close()
- local fileCount = 0
- for _ in pairs(chunkMap) do fileCount = fileCount + 1 end
- print("Found " .. fileCount .. " files in chunk map")
- print("")
- print("Verifying each file (this takes a while)...")
- print("")
- -- Verify each file
- local working = {}
- local broken = {}
- for path, chunks in pairs(chunkMap) do
- local chunkCount = 0
- for _ in pairs(chunks) do chunkCount = chunkCount + 1 end
- local allGood = true
- for chunkNum = 1, chunkCount do
- local info = chunks[chunkNum]
- if not info then
- allGood = false
- break
- end
- -- Try primary
- local response = sendRequest(info.primary, {
- id = generateRequestId(),
- action = "read",
- path = path,
- chunk = chunkNum
- })
- if response and response.success then
- -- Good!
- elseif info.mirror then
- -- Try mirror
- response = sendRequest(info.mirror, {
- id = generateRequestId(),
- action = "read",
- path = path,
- chunk = chunkNum
- })
- if not (response and response.success) then
- allGood = false
- break
- end
- else
- allGood = false
- break
- end
- end
- if allGood then
- table.insert(working, path)
- else
- table.insert(broken, path)
- end
- -- Progress
- local total = #working + #broken
- if total % 5 == 0 then
- term.clearLine()
- term.setCursorPos(1, select(2, term.getCursorPos()))
- write("Progress: " .. total .. "/" .. fileCount)
- end
- end
- -- Write detailed log to file
- local logFile = fs.open(LOG_FILE, "w")
- logFile.writeLine("=== NDisk Verification Results ===")
- logFile.writeLine("")
- logFile.writeLine("WORKING FILES (" .. #working .. "):")
- for _, path in ipairs(working) do
- logFile.writeLine(" + " .. path)
- end
- logFile.writeLine("")
- logFile.writeLine("BROKEN FILES (" .. #broken .. "):")
- for _, path in ipairs(broken) do
- logFile.writeLine(" X " .. path)
- end
- logFile.close()
- -- Show summary on screen
- print("")
- print("")
- print("========================================")
- term.setTextColor(colors.lime)
- print("WORKING: " .. #working .. " files")
- term.setTextColor(colors.red)
- print("BROKEN: " .. #broken .. " files")
- term.setTextColor(colors.white)
- print("========================================")
- print("")
- print("Full list saved to: " .. LOG_FILE)
- print("Run 'edit " .. LOG_FILE .. "' to view details")
- print("")
- if #broken > 0 then
- term.setTextColor(colors.yellow)
- print("CLEANUP OPTION:")
- print("Remove " .. #broken .. " broken entries from chunklocation.txt?")
- print("This ONLY removes entries that point to missing data.")
- print("A backup will be created first.")
- print("")
- write("Proceed? [y/N]: ")
- term.setTextColor(colors.white)
- local input = read()
- if input:lower() == "y" or input:lower() == "yes" then
- -- Backup first
- if fs.exists("chunklocation.txt.preverify") then
- fs.delete("chunklocation.txt.preverify")
- end
- fs.copy("chunklocation.txt", "chunklocation.txt.preverify")
- print("Backed up to chunklocation.txt.preverify")
- -- Create broken set for fast lookup
- local brokenSet = {}
- for _, path in ipairs(broken) do
- brokenSet[path] = true
- end
- -- Rewrite chunklocation.txt without broken entries
- local oldFile = fs.open("chunklocation.txt.preverify", "r")
- local newFile = fs.open("chunklocation.txt", "w")
- local removed = 0
- for line in oldFile.readLine do
- local parts = {}
- for part in line:gmatch("%S+") do
- table.insert(parts, part)
- end
- local filename = parts[1]
- if filename and not brokenSet[filename] then
- newFile.writeLine(line)
- else
- removed = removed + 1
- end
- end
- oldFile.close()
- newFile.close()
- term.setTextColor(colors.lime)
- print("Removed " .. removed .. " broken chunk entries")
- term.setTextColor(colors.white)
- else
- print("Cleanup skipped.")
- end
- end
- print("")
- print("Done. Next step: run ndisk_recover_from_disk")
- end
- main()
Advertisement
Add Comment
Please, Sign In to add comment