Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[ stortape program, provides storing and reading data from tapes (with optinal encryption and compression)
- Author: Bs()Dd (uses original "tape" program code by Bizzycola and Vexatos)
- ]]
- -- Encryption and compression is disabled in code now
- local component = require("component")
- local fs = require("filesystem")
- local shell = require("shell")
- local term = require("term")
- local args, options = shell.parse(...)
- if not component.isAvailable("data") then
- print("Data card is not found in system, AES and Compression not supported.")
- crst = nil
- else
- data = component.data
- if data.encrypt == nil then
- print("Data card Tier 1 is found in system, only Compression supported.")
- crst = false
- else
- print("Data card Tier 2 or 3 is found in system, AES and Compression supported.")
- crst = true
- end
- end
- local function printUsage()
- print("Usage:")
- print(" - 'stortape -r <start address> <file>' to record file to address in tape")
- print(" - 'stortape -l <start address> <end address> <save to>' to read file from address in tape and save")
- print("Rec & Load options:")
- print(" '--comp' to compression recording chunks (Tier 1 Data card required)")
- print(" '--dcom' to decompression reading chunks (Tier 1 Data card required)")
- print(" '--e' to effective compression by caching data to HDD (Minimum 1Mb free space required)")
- print(" also needs when decompressing effective compressed file")
- print(" '--b=<bytes>' to specify the size of the chunks the program will write to a tape")
- print(" '--eaes=<password>' to encrypt chunks by AES before rec (Tier 2 Data card required)")
- print(" '--daes=<password>' to decrypt chunks by AES before save (Tier 2 Data card required)")
- print(" '--v=<init. vector>' to set custom IV for AES encrypting")
- print(" '--address=<address>' to use a specific tape drive")
- print(" '-y' to not ask for confirmation before starting to write")
- return
- end
- local function confirm(msg)
- if not options.y then
- print(msg)
- print("Type `y` to confirm, `n` to cancel.")
- repeat
- local response = io.read()
- if response and response:lower():sub(1, 1) == "n" then
- print("Canceled.")
- return false
- end
- until response and response:lower():sub(1, 1) == "y"
- end
- return true
- end
- local function getTapeDrive()
- --Credits to gamax92 for this
- local tape
- if options.address then
- if type(options.address) ~= "string" then
- io.stderr:write("'address' may only be a string.")
- return
- end
- local fulladdr = component.get(options.address)
- if fulladdr == nil then
- io.stderr:write("No component at this address.")
- return
- end
- if component.type(fulladdr) ~= "tape_drive" then
- io.stderr:write("No tape drive at this address.")
- return
- end
- tape = component.proxy(fulladdr)
- else
- tape = component.tape_drive
- end
- return tape
- --End of gamax92's part
- end
- local tape = getTapeDrive()
- local function flate(mode, bytes)
- if mode == true then
- local flated= data.deflate(bytes)
- end
- if mode == false then
- local flated= data.inflate(bytes)
- end
- return flated
- end
- local function crypt(mode, bytes, passw, vector)
- if mode == true then
- local crypted = encrypt(bytes, passw, vector)
- end
- if mode == false then
- local crypted = decrypt(bytes, passw, vector)
- end
- return crypted
- end
- local function binit()
- if not tape.isReady() then
- io.stderr:write("Tape is not inserted.\n")
- os.exit()
- end
- if options.eaes or options.daes then
- if crst == false then
- io.stderr:write("Error: AES is not supported. Install Data card Tier 2\n")
- os.exit()
- else
- if options.eaes ~= nil then
- local passw = options.eaes
- else
- local passw = options.daes
- end
- if string.len(passw) % 16 ~= 0 then
- repeat
- passw = passw .. '_'
- until string.len(passw) % 16 == 0
- end
- end
- end
- if options.comp or options.dcom then
- if crst == nil then
- io.stderr:write("Error: Compression is not supported. Install Data card\n")
- os.exit()
- else
- print("Compression set.")
- end
- end
- local block = 2048
- if options.b then
- local nBlock = tonumber(options.b)
- if nBlock then
- print("Setting chunk size to " .. options.b)
- block = nBlock
- else
- io.stderr:write("option --b is not a number.\n")
- return
- end
- end
- local vect = "stortapevectorbr"
- if options.v then
- if string.len(options.v) % 16 ~= 0 then
- vect = options.v
- repeat
- vect = vect .. '_'
- until string.len(vect) % 16 == 0
- print("Setting IV value to " .. vect)
- else
- print("Setting IV value to " .. options.v)
- vect = options.v
- end
- end
- return block, passw, vect
- end
- local function record()
- local _, y
- local block, passw, vect = binit()
- tape.stop()
- tape.seek(-tape.getSize())
- tape.seek(tonumber(args[1]))
- tape.stop()
- local path = shell.resolve(args[2])
- size = fs.size(path)
- file, msg = io.open(path, "rb")
- if not file then
- io.stderr:write("Error: " .. msg)
- return
- end
- local free = tape.getSize() - args[1]
- print("Size of tape is: " .. tape.getSize())
- print("Bytes to end: " .. free)
- print("Path of file: " .. path)
- print("Size of file: " .. size)
- local bytery = 0
- if size > tape.getSize() then
- io.stderr:write("Tape size is not enough to copy.\n")
- os.exit()
- end
- if options.comp or options.eaes then
- if size < tape.getSize() and size > tape.getSize()-2048 then
- if not confirm("Warning: File may not fit on tape after AES/Compression. Continue?") then return end
- end
- end
- if not confirm("Are you sure you want to write to this tape?") then return end
- local function fancyNumber(n)
- return tostring(math.floor(n)):reverse():gsub("(%d%d%d)", "%1,"):gsub("%D$", ""):reverse()
- end
- _, y = term.getCursor()
- repeat
- local bytes = file:read(block)
- if bytes and #bytes > 0 then
- if not tape.isReady() then
- io.stderr:write("\nError: Tape was removed during writing.\n")
- file:close()
- return
- end
- term.setCursor(1, y)
- bytery = bytery + #bytes
- term.write(string.format("Write %s byte...", fancyNumber(bytery)))
- tape.write(bytes)
- end
- until not bytes or bytery > size
- file:close()
- tape.stop()
- tape.seek(-tape.getSize())
- tape.stop()
- print("\nDone. REMIND FILE ADDRESS: " .. args[1] .. " " .. args[1]+bytery-1)
- end
- local function lload()
- local _, y
- local block, passw, vect = binit()
- tape.stop()
- tape.seek(-tape.getSize())
- tape.seek(tonumber(args[1]))
- tape.stop()
- local path = shell.resolve(args[3])
- size = args[2]-args[1]+1
- file, msg = io.open(path, "w")
- if not file then
- io.stderr:write("Error: " .. msg)
- return
- end
- print("Size of tape is: " .. tape.getSize())
- print("Path of file: " .. path)
- print("Size of file: " .. size)
- local bytery = 0
- if not confirm("Are you sure you want to write to computer?") then return end
- local function fancyNumber(n)
- return tostring(math.floor(n)):reverse():gsub("(%d%d%d)", "%1,"):gsub("%D$", ""):reverse()
- end
- _, y = term.getCursor()
- local szcut = size
- repeat
- local bytes = tape.read(block)
- if bytes and #bytes > 0 then
- if not tape.isReady() then
- io.stderr:write("\nError: Tape was removed during reading.\n")
- file:close()
- return
- end
- term.setCursor(1, y)
- bytery = bytery + #bytes
- local displaySize = math.min(bytery, size)
- term.write(string.format("Write %s of %s bytes... (%.2f %%)", fancyNumber(displaySize), fancyNumber(size), 100 * displaySize / size))
- if not bytes or bytery > size then
- print(szcut)
- cutbytes = string.sub(bytes, 0, szcut)
- file:write(cutbytes)
- else
- file:write(bytes)
- szcut = szcut - block
- end
- end
- until not bytes or bytery > size
- file:close()
- tape.stop()
- tape.seek(-tape.getSize())
- tape.stop()
- print("\nDone. File saved.")
- end
- if options.r and args[1] and args[2] then
- record()
- elseif options.l and args[1] and args[2] and args[3] then
- lload()
- else
- printUsage()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement