Advertisement
VlaD00m

stortape.lua

Aug 20th, 2020
1,014
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.21 KB | None | 0 0
  1. --[[ stortape program, provides storing and reading data from tapes (with optinal encryption and compression)
  2. Author: Bs()Dd (uses original "tape" program code by Bizzycola and Vexatos)
  3. ]]
  4. -- Encryption and compression is disabled in code now
  5. local component = require("component")
  6. local fs = require("filesystem")
  7. local shell = require("shell")
  8. local term = require("term")
  9.  
  10. local args, options = shell.parse(...)
  11.  
  12. if not component.isAvailable("data") then
  13.   print("Data card is not found in system, AES and Compression not supported.")
  14.   crst = nil
  15. else
  16.   data = component.data
  17.   if data.encrypt == nil then
  18.     print("Data card Tier 1 is found in system, only Compression supported.")
  19.     crst = false
  20.   else
  21.     print("Data card Tier 2 or 3 is found in system, AES and Compression supported.")
  22.     crst = true
  23.   end
  24. end
  25.  
  26. local function printUsage()
  27.   print("Usage:")
  28.   print(" - 'stortape -r <start address> <file>' to record file to address in tape")
  29.   print(" - 'stortape -l <start address> <end address> <save to>' to read file from address in tape and save")
  30.   print("Rec & Load options:")
  31.   print(" '--comp' to compression recording chunks (Tier 1 Data card required)")
  32.   print(" '--dcom' to decompression reading chunks (Tier 1 Data card required)")
  33.   print(" '--e' to effective compression by caching data to HDD (Minimum 1Mb free space required)")
  34.   print("       also needs when decompressing effective compressed file")
  35.   print(" '--b=<bytes>' to specify the size of the chunks the program will write to a tape")
  36.   print(" '--eaes=<password>' to encrypt chunks by AES before rec (Tier 2 Data card required)")
  37.   print(" '--daes=<password>' to decrypt chunks by AES before save (Tier 2 Data card required)")
  38.   print(" '--v=<init. vector>' to set custom IV for AES encrypting")
  39.   print(" '--address=<address>' to use a specific tape drive")
  40.   print(" '-y' to not ask for confirmation before starting to write")
  41.   return
  42. end
  43.  
  44. local function confirm(msg)
  45.   if not options.y then
  46.     print(msg)
  47.     print("Type `y` to confirm, `n` to cancel.")
  48.     repeat
  49.       local response = io.read()
  50.       if response and response:lower():sub(1, 1) == "n" then
  51.         print("Canceled.")
  52.         return false
  53.       end
  54.     until response and response:lower():sub(1, 1) == "y"
  55.   end
  56.   return true
  57. end
  58.  
  59. local function getTapeDrive()
  60.   --Credits to gamax92 for this
  61.   local tape
  62.   if options.address then
  63.     if type(options.address) ~= "string" then
  64.       io.stderr:write("'address' may only be a string.")
  65.       return
  66.     end
  67.     local fulladdr = component.get(options.address)
  68.     if fulladdr == nil then
  69.       io.stderr:write("No component at this address.")
  70.       return
  71.     end
  72.     if component.type(fulladdr) ~= "tape_drive" then
  73.       io.stderr:write("No tape drive at this address.")
  74.       return
  75.     end
  76.     tape = component.proxy(fulladdr)
  77.   else
  78.     tape = component.tape_drive
  79.   end
  80.   return tape
  81.   --End of gamax92's part
  82. end
  83.  
  84. local tape = getTapeDrive()
  85.  
  86. local function flate(mode, bytes)
  87. if mode == true then
  88. local flated= data.deflate(bytes)
  89. end
  90. if mode == false then
  91. local flated= data.inflate(bytes)
  92. end
  93. return flated
  94. end
  95.  
  96. local function crypt(mode, bytes, passw, vector)
  97.  
  98. if mode == true then
  99. local crypted = encrypt(bytes, passw, vector)
  100. end
  101. if mode == false then
  102. local crypted = decrypt(bytes, passw, vector)
  103. end
  104. return crypted
  105. end
  106.  
  107. local function binit()
  108. if not tape.isReady() then
  109.     io.stderr:write("Tape is not inserted.\n")
  110.     os.exit()
  111. end
  112. if options.eaes or options.daes then
  113.   if crst == false then
  114.   io.stderr:write("Error: AES is not supported. Install Data card Tier 2\n")
  115.   os.exit()
  116.   else
  117.     if options.eaes ~= nil then
  118.       local passw = options.eaes
  119.     else
  120.       local passw = options.daes
  121.     end
  122.     if string.len(passw) % 16 ~= 0 then
  123.         repeat
  124.           passw = passw .. '_'
  125.         until string.len(passw) % 16 == 0
  126.     end
  127.   end
  128. end
  129. if options.comp or options.dcom then
  130.   if crst == nil then
  131.   io.stderr:write("Error: Compression is not supported. Install Data card\n")
  132.   os.exit()
  133.   else
  134.   print("Compression set.")
  135.   end
  136. end
  137. local block = 2048
  138.   if options.b then
  139.     local nBlock = tonumber(options.b)
  140.     if nBlock then
  141.       print("Setting chunk size to " .. options.b)
  142.       block = nBlock
  143.     else
  144.       io.stderr:write("option --b is not a number.\n")
  145.       return
  146.     end
  147.   end
  148. local vect = "stortapevectorbr"
  149. if options.v then
  150.     if string.len(options.v) % 16 ~= 0 then
  151.       vect = options.v
  152.       repeat
  153.         vect = vect .. '_'
  154.       until string.len(vect) % 16 == 0
  155.       print("Setting IV value to " .. vect)
  156.     else
  157.       print("Setting IV value to " .. options.v)
  158.       vect = options.v
  159.     end
  160. end
  161. return block, passw, vect
  162. end
  163.  
  164. local function record()
  165.   local _, y
  166.   local block, passw, vect = binit()
  167.   tape.stop()
  168.   tape.seek(-tape.getSize())
  169.   tape.seek(tonumber(args[1]))
  170.   tape.stop()
  171.   local path = shell.resolve(args[2])
  172.   size = fs.size(path)
  173.   file, msg = io.open(path, "rb")
  174.   if not file then
  175.     io.stderr:write("Error: " .. msg)
  176.     return
  177.   end
  178.   local free = tape.getSize() - args[1]
  179.   print("Size of tape is: " .. tape.getSize())
  180.   print("Bytes to end: " .. free)
  181.   print("Path of file: " .. path)
  182.   print("Size of file: " .. size)
  183.   local bytery = 0
  184.   if size > tape.getSize() then
  185.     io.stderr:write("Tape size is not enough to copy.\n")
  186.     os.exit()
  187.   end
  188.   if options.comp or options.eaes then
  189.     if size < tape.getSize() and size > tape.getSize()-2048 then
  190.       if not confirm("Warning: File may not fit on tape after AES/Compression. Continue?") then return end
  191.     end
  192.   end
  193.  
  194.   if not confirm("Are you sure you want to write to this tape?") then return end
  195.  
  196.   local function fancyNumber(n)
  197.     return tostring(math.floor(n)):reverse():gsub("(%d%d%d)", "%1,"):gsub("%D$", ""):reverse()
  198.   end
  199.   _, y = term.getCursor()
  200.   repeat
  201.     local bytes = file:read(block)
  202.     if bytes and #bytes > 0 then
  203.       if not tape.isReady() then
  204.         io.stderr:write("\nError: Tape was removed during writing.\n")
  205.         file:close()
  206.         return
  207.       end
  208.       term.setCursor(1, y)
  209.       bytery = bytery + #bytes
  210.       term.write(string.format("Write %s byte...", fancyNumber(bytery)))
  211.       tape.write(bytes)
  212.     end
  213.   until not bytes or bytery > size
  214.   file:close()
  215.   tape.stop()
  216.   tape.seek(-tape.getSize())
  217.   tape.stop()
  218.   print("\nDone. REMIND FILE ADDRESS: " .. args[1] .. " " .. args[1]+bytery-1)
  219. end
  220.  
  221. local function lload()
  222.   local _, y
  223.   local block, passw, vect = binit()
  224.   tape.stop()
  225.   tape.seek(-tape.getSize())
  226.   tape.seek(tonumber(args[1]))
  227.   tape.stop()
  228.   local path = shell.resolve(args[3])
  229.   size = args[2]-args[1]+1
  230.   file, msg = io.open(path, "w")
  231.   if not file then
  232.     io.stderr:write("Error: " .. msg)
  233.     return
  234.   end
  235.   print("Size of tape is: " .. tape.getSize())
  236.   print("Path of file: " .. path)
  237.   print("Size of file: " .. size)
  238.   local bytery = 0
  239.  
  240.   if not confirm("Are you sure you want to write to computer?") then return end
  241.  
  242.   local function fancyNumber(n)
  243.     return tostring(math.floor(n)):reverse():gsub("(%d%d%d)", "%1,"):gsub("%D$", ""):reverse()
  244.   end
  245.  
  246.   _, y = term.getCursor()
  247.   local szcut = size
  248.   repeat
  249.     local bytes = tape.read(block)
  250.     if bytes and #bytes > 0 then
  251.       if not tape.isReady() then
  252.         io.stderr:write("\nError: Tape was removed during reading.\n")
  253.         file:close()
  254.         return
  255.       end
  256.       term.setCursor(1, y)
  257.       bytery = bytery + #bytes
  258.       local displaySize = math.min(bytery, size)
  259.       term.write(string.format("Write %s of %s bytes... (%.2f %%)", fancyNumber(displaySize), fancyNumber(size), 100 * displaySize / size))
  260.       if not bytes or bytery > size then
  261.       print(szcut)
  262.         cutbytes = string.sub(bytes, 0, szcut)
  263.         file:write(cutbytes)
  264.       else
  265.         file:write(bytes)
  266.         szcut = szcut - block
  267.       end
  268.     end
  269.   until not bytes or bytery > size
  270.   file:close()
  271.   tape.stop()
  272.   tape.seek(-tape.getSize())
  273.   tape.stop()
  274.   print("\nDone. File saved.")
  275. end
  276.  
  277. if options.r and args[1] and args[2] then
  278.   record()
  279. elseif options.l and args[1] and args[2] and args[3] then
  280.   lload()
  281. else
  282.   printUsage()
  283. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement