Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- VirtualFSLayer - NFS Server
- -- NFS sync method:
- -- Step1 / C->S: Request to connect
- -- Step2 / S->C: Send challenge
- -- Step3 / C->S: Send response
- -- Step4 / S->C: Get SHA1 hash of all files on local store,
- -- Client: Check which versions differ,
- -- Step5 / C->S: transmit newer versions if necessary and list of files to get
- -- Client: Write their versions of files to cache if necessary.
- -- Step6 / S->C: transmit newer versions if necessary.
- -- Authentication is Client->Server only
- local args = {...}
- if (not base64) and (not os.loadAPI("base64")) then
- if http then
- local h = http.get("http://pastebin.com/raw.php?i=pp3kpb19")
- if h then
- local data = h.readAll()
- h.close()
- local f = fs.open("base64", "w")
- f.write(data)
- f.close()
- if not os.loadAPI("base64") then
- error("Could not load base64 API!")
- end
- else
- error("Could not load base64 API!")
- end
- else
- error("Could not load base64 API!")
- end
- end
- if args[1] then
- print("Running with password authentication enabled.")
- if not (SHA2 or os.loadAPI("SHA2")) then
- error("Could not load SHA2 library!")
- end
- else
- print("Running with password authentication disabled.")
- end
- if not (SHA1 or os.loadAPI("SHA1")) then
- if http then
- local h = http.get("http://pastebin.com/raw.php?i=QvtjCy9h")
- if h then
- local data = h.readAll()
- h.close()
- local f = fs.open("SHA1", "w")
- f.write(data)
- f.close()
- if not os.loadAPI("SHA1") then
- error("Could not load SHA1 API!")
- end
- else
- error("Could not load SHA1 API!")
- end
- else
- error("Could not load SHA1 API!")
- end
- end
- local filestorePath = "server/"
- local NFSChannel = 0xDA7A
- local NFSIdent = "NetFS"
- local syncAttempts = {}
- local basePW = {}
- local fileHashCache = {} -- SHA1 hashes of all files in the cache
- local fileTimestamps = {} -- Time
- -- Timestamps are: {os.day(), os.time()}
- if not fs.exists(filestorePath) then
- fs.makeDir(filestorePath)
- end
- if args[1] then
- for i=1, #args[1] do
- basePW[i] = string.byte(args[1], i, i)
- end
- end
- local modem = false
- for i=1, 6 do
- local side = rs.getSides()[i]
- if peripheral.isPresent(side) and (peripheral.getType(side) == "modem") then
- print("Found modem on "..side)
- modem = peripheral.wrap(side)
- modem.open(NFSChannel)
- break
- end
- end
- local function updateCache()
- print("Updating hash cache...")
- function recursiveTraverse(dir)
- local listing = fs.list(dir)
- local dirs = {}
- local files = {}
- for i=1, #listing do
- if fs.isDir(listing[i]) then
- table.insert(dirs, listing[i])
- local f2, d2 = recursiveTraverse(fs.combine(dir, listing[i]))
- for i2=1, #f2 do
- table.insert(files, f2[i])
- end
- for i2=1, #d2 do
- table.insert(dirs, d2[i])
- end
- else
- table.insert(files, fs.combine(dir, listing[i]))
- end
- end
- return files, dirs
- end
- local cacheListing, dirListing = recursiveTraverse(filestorePath)
- for i=1, #cacheListing do
- local subPath = string.sub(cacheListing[i], #filestorePath)
- subPath = string.gsub(subPath, "\\", "/")
- if string.sub(subPath, 1, 1) == "/" then subPath = string.sub(subPath, 2) end
- if string.sub(subPath, #subPath, #subPath) == "/" then subPath = string.sub(subPath, 1, #subPath-1) end
- local f = fs.open(cacheListing[i], "rb")
- local d = {}
- local lastPause = os.clock()
- while true do
- local byte = f.read()
- if byte then
- table.insert(d, byte)
- else
- break
- end
- if (os.clock() - lastPause) >= 2.90 then
- os.queueEvent("")
- os.pullEvent("")
- lastPause = os.clock()
- end
- end
- f.close()
- local currentHash = SHA1.digest2str(SHA1.digest(d))
- if fileHashCache[subPath] ~= currentHash then
- fileTimestamps[subPath] = {os.day(), os.time()}
- fileHashCache[subPath] = currentHash
- end
- os.sleep(0)
- end
- print("Finished updating hash cache.")
- end
- if modem then
- updateCache()
- while true do
- local _, side, sCh, rCh, msg = os.pullEvent("modem_message")
- msg = textutils.unserialize(msg)
- if type(msg) == "table" then
- --print("Got message, ident is "..msg[1].." from "..msg[2].." addressed to "..msg[3])
- if (msg[1] == NFSIdent) and (msg[3] == os.computerID()) then
- local id = msg[2]
- if msg[4] == "Step1" then -- Auth request
- print("Got auth request from "..id)
- if args[1] then
- if not syncAttempts[id] then
- syncAttempts[id] = {{}, {}}
- local cResponse = {}
- for i=1, #basePW do
- table.insert(cResponse, basePW[i])
- end
- for i=1, 16 do
- syncAttempts[id][1][i] = math.random(0, 255)
- table.insert(cResponse, syncAttempts[id][1][i])
- end
- --print("Sending step 2 to "..id)
- modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step2", syncAttempts[id][1]}))
- syncAttempts[id][2] = SHA2.digest(cResponse)
- --print("Sent step 2.")
- end
- else -- Skip to step4:
- --print("Sending step 4 to "..id)
- modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step4", fileHashCache, fileTimestamps}))
- end
- elseif msg[4] == "Step3" then -- Get response
- print("Got auth response from "..id)
- if syncAttempts[id][2] then
- local response = msg[5]
- local ok = true
- for i=1, #msg[5] do
- if response[i] ~= msg[5][i] then
- ok = false
- break
- end
- end
- syncAttempts[id] = nil
- if ok then
- --print("Sending step 4 to "..id)
- modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step4", fileHashCache, fileTimestamps}))
- --print("Sent step 4.")
- else
- --print("Sending auth failure to "..id)
- modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "AuthFailed"}))
- --print("Sent auth failure.")
- end
- end
- elseif msg[4] == "Step5" then -- Get newer files / file list
- print("Got changed file listing from "..id)
- local fSendList = msg[6] -- Files to send to the client
- local newFileList = msg[5] -- New versions of files
- local fSendData = {} -- File data to send to client
- local nSendList = 0
- local nFileList = 0
- for i,v in pairs(newFileList) do
- nFileList = nFileList+1
- end
- for i,v in pairs(fSendList) do
- nSendList = nSendList+1
- end
- print(nSendList.." files to send to client, ")
- print(nFileList.." files to locally overwrite.")
- for i,v in pairs(newFileList) do
- local fullPath = fs.combine(filestorePath, i)
- local fullBaseDir = string.sub(fullPath, 1, (#fullPath-#fs.getName(fullPath)))
- if not fs.exists(fullBaseDir) then
- fs.makeDir(fullBaseDir)
- end
- if string.sub(v, 1, 7) == "BINARY:" then
- local data = base64.decode(string.sub(v, 8))
- local lastPause = os.clock()
- local f = fs.open(fullPath, "wb")
- for i=1, #data do
- f.write(data[i])
- if (os.clock() - lastPause) >= 2.90 then
- os.queueEvent("")
- os.pullEvent("")
- lastPause = os.clock()
- end
- end
- f.close()
- else
- local f = fs.open(fullPath, "w")
- f.write(v)
- f.close()
- end
- end
- for i,v in pairs(fSendList) do
- local f = fs.open(fs.combine(filestorePath, i), "rb")
- local text = true
- local lastPause = os.clock()
- local data = {}
- local dataStr = ""
- while true do
- local byte = f.read()
- if byte then
- if (byte < 0x20) or (byte > 0x7E) then
- text = false
- end
- table.insert(data, byte)
- if text then
- dataStr = dataStr..string.char(byte)
- end
- else
- break
- end
- if (os.clock() - lastPause) >= 2.90 then
- os.queueEvent("")
- os.pullEvent("")
- lastPause = os.clock()
- end
- end
- f.close()
- if not text then
- dataStr = "BINARY:"..base64.encode(data)
- end
- fSendData[i] = dataStr
- end
- --print("Sending step 6 to "..id)
- modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step6", fSendData}))
- --print("Sent step 6.")
- updateCache()
- end
- end
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement