Advertisement
Tatantyler

VirtualFSLayer - NFS Server

Jul 29th, 2013
497
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.30 KB | None | 0 0
  1. -- VirtualFSLayer - NFS Server
  2.  
  3. -- NFS sync method:
  4. -- Step1 / C->S: Request to connect
  5. -- Step2 / S->C: Send challenge
  6. -- Step3 / C->S: Send response
  7. -- Step4 / S->C: Get SHA1 hash of all files on local store,
  8. -- Client: Check which versions differ,
  9. -- Step5 / C->S: transmit newer versions if necessary and list of files to get
  10. -- Client: Write their versions of files to cache if necessary.
  11. -- Step6 / S->C: transmit newer versions if necessary.
  12.  
  13. -- Authentication is Client->Server only
  14.  
  15. local args = {...}
  16.  
  17. if (not base64) and (not os.loadAPI("base64")) then
  18.     if http then
  19.         local h = http.get("http://pastebin.com/raw.php?i=pp3kpb19")
  20.         if h then
  21.             local data = h.readAll()
  22.             h.close()
  23.             local f = fs.open("base64", "w")
  24.             f.write(data)
  25.             f.close()
  26.             if not os.loadAPI("base64") then
  27.                 error("Could not load base64 API!")
  28.             end
  29.         else
  30.             error("Could not load base64 API!")
  31.         end
  32.     else
  33.         error("Could not load base64 API!")
  34.     end
  35. end
  36.  
  37. if args[1] then
  38.     print("Running with password authentication enabled.")
  39.     if not (SHA2 or os.loadAPI("SHA2")) then
  40.         error("Could not load SHA2 library!")
  41.     end
  42. else
  43.     print("Running with password authentication disabled.")
  44. end
  45.  
  46. if not (SHA1 or os.loadAPI("SHA1")) then
  47.     if http then
  48.         local h = http.get("http://pastebin.com/raw.php?i=QvtjCy9h")
  49.         if h then
  50.             local data = h.readAll()
  51.             h.close()
  52.             local f = fs.open("SHA1", "w")
  53.             f.write(data)
  54.             f.close()
  55.             if not os.loadAPI("SHA1") then
  56.                 error("Could not load SHA1 API!")
  57.             end
  58.         else
  59.             error("Could not load SHA1 API!")
  60.         end
  61.     else
  62.         error("Could not load SHA1 API!")
  63.     end
  64. end
  65.  
  66. local filestorePath = "server/"
  67. local NFSChannel = 0xDA7A
  68. local NFSIdent = "NetFS"
  69.  
  70. local syncAttempts = {}
  71. local basePW = {}
  72.  
  73. local fileHashCache = {} -- SHA1 hashes of all files in the cache
  74. local fileTimestamps = {} -- Time
  75. -- Timestamps are: {os.day(), os.time()}
  76.  
  77. if not fs.exists(filestorePath) then
  78.     fs.makeDir(filestorePath)
  79. end
  80.  
  81. if args[1] then
  82.     for i=1, #args[1] do
  83.         basePW[i] = string.byte(args[1], i, i)
  84.     end
  85. end
  86.  
  87. local modem = false
  88.  
  89. for i=1, 6 do
  90.     local side = rs.getSides()[i]
  91.     if peripheral.isPresent(side) and (peripheral.getType(side) == "modem") then
  92.         print("Found modem on "..side)
  93.         modem = peripheral.wrap(side)
  94.         modem.open(NFSChannel)
  95.         break
  96.     end
  97. end
  98.  
  99. local function updateCache()
  100.     print("Updating hash cache...")
  101.     function recursiveTraverse(dir)
  102.         local listing = fs.list(dir)
  103.         local dirs = {}
  104.         local files = {}
  105.         for i=1, #listing do
  106.             if fs.isDir(listing[i]) then
  107.                 table.insert(dirs, listing[i])
  108.                 local f2, d2 = recursiveTraverse(fs.combine(dir, listing[i]))
  109.                 for i2=1, #f2 do
  110.                     table.insert(files, f2[i])
  111.                 end
  112.                 for i2=1, #d2 do
  113.                     table.insert(dirs, d2[i])
  114.                 end
  115.             else
  116.                 table.insert(files, fs.combine(dir, listing[i]))
  117.             end
  118.         end
  119.         return files, dirs
  120.     end
  121.     local cacheListing, dirListing = recursiveTraverse(filestorePath)
  122.     for i=1, #cacheListing do
  123.         local subPath = string.sub(cacheListing[i], #filestorePath)
  124.         subPath = string.gsub(subPath, "\\", "/")
  125.         if string.sub(subPath, 1, 1) == "/" then subPath = string.sub(subPath, 2) end
  126.         if string.sub(subPath, #subPath, #subPath) == "/" then subPath = string.sub(subPath, 1, #subPath-1) end
  127.         local f = fs.open(cacheListing[i], "rb")
  128.         local d = {}
  129.         local lastPause = os.clock()
  130.         while true do
  131.             local byte = f.read()
  132.             if byte then
  133.                 table.insert(d, byte)
  134.             else
  135.                 break
  136.             end
  137.             if (os.clock() - lastPause) >= 2.90 then
  138.                 os.queueEvent("")
  139.                 os.pullEvent("")
  140.                 lastPause = os.clock()
  141.             end
  142.         end
  143.         f.close()
  144.         local currentHash = SHA1.digest2str(SHA1.digest(d))
  145.         if fileHashCache[subPath] ~= currentHash then
  146.             fileTimestamps[subPath] = {os.day(), os.time()}
  147.             fileHashCache[subPath] = currentHash
  148.         end
  149.         os.sleep(0)
  150.     end
  151.     print("Finished updating hash cache.")
  152. end
  153.  
  154. if modem then
  155.     updateCache()
  156.     while true do
  157.         local _, side, sCh, rCh, msg = os.pullEvent("modem_message")
  158.         msg = textutils.unserialize(msg)
  159.         if type(msg) == "table" then
  160.             --print("Got message, ident is "..msg[1].." from "..msg[2].." addressed to "..msg[3])
  161.             if (msg[1] == NFSIdent) and (msg[3] == os.computerID()) then
  162.                 local id = msg[2]
  163.                 if msg[4] == "Step1" then -- Auth request
  164.                     print("Got auth request from "..id)
  165.                     if args[1] then
  166.                         if not syncAttempts[id] then
  167.                             syncAttempts[id] = {{}, {}}
  168.                             local cResponse = {}
  169.                             for i=1, #basePW do
  170.                                 table.insert(cResponse, basePW[i])
  171.                             end
  172.                             for i=1, 16 do
  173.                                 syncAttempts[id][1][i] = math.random(0, 255)
  174.                                 table.insert(cResponse, syncAttempts[id][1][i])
  175.                             end
  176.                             --print("Sending step 2 to "..id)
  177.                             modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step2", syncAttempts[id][1]}))
  178.                             syncAttempts[id][2] = SHA2.digest(cResponse)
  179.                             --print("Sent step 2.")
  180.                         end
  181.                     else -- Skip to step4:
  182.                         --print("Sending step 4 to "..id)
  183.                         modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step4", fileHashCache, fileTimestamps}))
  184.                     end
  185.                 elseif msg[4] == "Step3" then -- Get response
  186.                     print("Got auth response from "..id)
  187.                     if syncAttempts[id][2] then
  188.                         local response = msg[5]
  189.                         local ok = true
  190.                         for i=1, #msg[5] do
  191.                             if response[i] ~= msg[5][i] then
  192.                                 ok = false
  193.                                 break
  194.                             end
  195.                         end
  196.                         syncAttempts[id] = nil
  197.                         if ok then
  198.                             --print("Sending step 4 to "..id)
  199.                             modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step4", fileHashCache, fileTimestamps}))
  200.                             --print("Sent step 4.")
  201.                         else
  202.                             --print("Sending auth failure to "..id)
  203.                             modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "AuthFailed"}))
  204.                             --print("Sent auth failure.")
  205.                         end
  206.                     end
  207.                 elseif msg[4] == "Step5" then -- Get newer files / file list
  208.                     print("Got changed file listing from "..id)
  209.                     local fSendList = msg[6] -- Files to send to the client
  210.                     local newFileList = msg[5] -- New versions of files
  211.                     local fSendData = {} -- File data to send to client
  212.                     local nSendList = 0
  213.                     local nFileList = 0
  214.                     for i,v in pairs(newFileList) do
  215.                         nFileList = nFileList+1
  216.                     end
  217.                     for i,v in pairs(fSendList) do
  218.                         nSendList = nSendList+1
  219.                     end
  220.                     print(nSendList.." files to send to client, ")
  221.                     print(nFileList.." files to locally overwrite.")
  222.                     for i,v in pairs(newFileList) do
  223.                         local fullPath = fs.combine(filestorePath, i)
  224.                         local fullBaseDir = string.sub(fullPath, 1, (#fullPath-#fs.getName(fullPath)))
  225.                         if not fs.exists(fullBaseDir) then
  226.                             fs.makeDir(fullBaseDir)
  227.                         end
  228.                         if string.sub(v, 1, 7) == "BINARY:" then
  229.                             local data = base64.decode(string.sub(v, 8))
  230.                             local lastPause = os.clock()
  231.                             local f = fs.open(fullPath, "wb")
  232.                             for i=1, #data do
  233.                                 f.write(data[i])
  234.                                 if (os.clock() - lastPause) >= 2.90 then
  235.                                     os.queueEvent("")
  236.                                     os.pullEvent("")
  237.                                     lastPause = os.clock()
  238.                                 end
  239.                             end
  240.                             f.close()
  241.                         else
  242.                             local f = fs.open(fullPath, "w")
  243.                             f.write(v)
  244.                             f.close()
  245.                         end
  246.                     end
  247.                     for i,v in pairs(fSendList) do
  248.                         local f = fs.open(fs.combine(filestorePath, i), "rb")
  249.                         local text = true
  250.                         local lastPause = os.clock()
  251.                         local data = {}
  252.                         local dataStr = ""
  253.                         while true do
  254.                             local byte = f.read()
  255.                             if byte then
  256.                                 if (byte < 0x20) or (byte > 0x7E) then
  257.                                     text = false
  258.                                 end
  259.                                 table.insert(data, byte)
  260.                                 if text then
  261.                                     dataStr = dataStr..string.char(byte)
  262.                                 end
  263.                             else
  264.                                 break
  265.                             end
  266.                             if (os.clock() - lastPause) >= 2.90 then
  267.                                 os.queueEvent("")
  268.                                 os.pullEvent("")
  269.                                 lastPause = os.clock()
  270.                             end
  271.                         end
  272.                         f.close()
  273.                         if not text then
  274.                             dataStr = "BINARY:"..base64.encode(data)
  275.                         end
  276.                         fSendData[i] = dataStr
  277.                     end
  278.                     --print("Sending step 6 to "..id)
  279.                     modem.transmit(NFSChannel, NFSChannel, textutils.serialize({NFSIdent, os.computerID(), id, "Step6", fSendData}))
  280.                     --print("Sent step 6.")
  281.                     updateCache()
  282.                 end
  283.             end
  284.         end
  285.     end
  286. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement