Advertisement
CrazedProgrammer

tfs

Dec 28th, 2016
232
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.25 KB | None | 0 0
  1. --[[
  2. tfs version 1.0.0
  3.  
  4. The MIT License (MIT)
  5. Copyright (c) 2016 CrazedProgrammer
  6.  
  7. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  8. associated documentation files (the "Software"), to deal in the Software without restriction,
  9. including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
  11. so, subject to the following conditions:
  12.  
  13. The above copyright notice and this permission notice shall be included in all copies or
  14. substantial portions of the Software.
  15.  
  16. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  17. INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  18. PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19. COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  20. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. ]]
  23.  
  24. local _fs = { }
  25. for k, v in pairs(_G.fs) do
  26.     _fs[k] = v
  27. end
  28. for k, _ in pairs(_fs) do
  29.     _G.fs[k] = nil
  30. end
  31.  
  32. local fsTree = { }
  33.  
  34. local function getPath(path)
  35.     if path == "" or path == "/" then return "" end
  36.     if _fs.getDir(path) == "" then
  37.         return _fs.getName(path)
  38.     else
  39.         return _fs.getDir(path).."/".._fs.getName(path)
  40.     end
  41. end
  42.  
  43. local function getParts(path)
  44.     path = getPath(path)
  45.     if path == "" then return { } end
  46.     local parts, index = { }, 1
  47.     for i = 1, #path do
  48.         if path:sub(i, i) == "/" then
  49.             parts[#parts + 1] = path:sub(index, i - 1)
  50.             index = i + 1
  51.         end
  52.     end
  53.     parts[#parts + 1] = path:sub(index, #path)
  54.     return parts
  55. end
  56.  
  57. local function access(path)
  58.     local parts = getParts(path)
  59.     if parts[1] ~= "rom" then
  60.         local current = fsTree
  61.         for i = 1, #parts do
  62.             if type(current) == "table" then
  63.                 if current[parts[i]] then
  64.                     current = current[parts[i]]
  65.                 else
  66.                     return nil
  67.                 end
  68.             else
  69.                 return nil
  70.             end
  71.         end
  72.         if type(current) == "table" then
  73.             local t = { }
  74.             for k, _ in pairs(current) do
  75.                 t[#t + 1] = k
  76.             end
  77.             if #parts == 0 then
  78.                 t[#t + 1] = "rom"
  79.             end
  80.             return t
  81.         else
  82.             return current
  83.         end
  84.     else
  85.         if _fs.exists(path) then
  86.             if _fs.isDir(path) then
  87.                 return _fs.list(path)
  88.             else
  89.                 local handle = _fs.open(path, "r")
  90.                 local data = handle.readAll()
  91.                 handle.close()
  92.                 return data
  93.             end
  94.         else
  95.             return nil
  96.         end
  97.     end
  98. end
  99.  
  100. function fs.list(path)
  101.     local dir = access(path)
  102.     if type(dir) == "table" then
  103.         return dir
  104.     else
  105.         error("Not a directory")
  106.     end
  107. end
  108.  
  109. function fs.exists(path)
  110.     return access(path) ~= nil
  111. end
  112.  
  113. function fs.isDir(path)
  114.     return type(access(path)) == "table"
  115. end
  116.  
  117. function fs.isReadOnly(path)
  118.     return getParts(path)[1] == "rom"
  119. end
  120.  
  121. fs.getName = _fs.getName
  122.  
  123. function fs.getDrive(path)
  124.     if not access(path) then return nil end
  125.     return (getParts(path)[1] == "rom") and "rom" or "hdd"
  126. end
  127.  
  128. function fs.getSize(path)
  129.     local file = access(path)
  130.     if type(file) == "string" then
  131.         return #file
  132.     elseif file == nil then
  133.         error("No such file")
  134.     else
  135.         return 0
  136.     end
  137. end
  138.  
  139. function fs.getFreeSpace(path)
  140.     return (getParts(path)[1] == "rom") and 0 or 99999999
  141. end
  142.  
  143. function fs.makeDir(path)
  144.     local parts = getParts(path)
  145.     if parts[1] ~= "rom" then
  146.         local current = fsTree
  147.         for i = 1, #parts do
  148.             if type(current[parts[i]]) ~= "string" then
  149.                 if type(current[parts[i]]) == "nil" then
  150.                     current[parts[i]] = { }
  151.                 end
  152.                 current = current[parts[i]]
  153.             else
  154.                 error("File exists")
  155.             end
  156.         end
  157.     else
  158.         error("Access Denied") -- great consistency you've got there, Dan
  159.         -- really, this is pleasing my OCD
  160.     end
  161. end
  162.  
  163. function fs.delete(path)
  164.     local parts = getParts(path)
  165.     if parts[1] ~= "rom" then
  166.         local current = fsTree
  167.         for i = 1, #parts do
  168.             if i == #parts then
  169.                 current[parts[i]] = nil
  170.             elseif type(current[parts[i]]) == "table" then
  171.                 current = current[parts[i]]
  172.             else
  173.                 return
  174.             end
  175.         end
  176.     else
  177.         error("Access Denied")
  178.     end
  179. end
  180.  
  181. function fs.move(frompath, topath)
  182.     local data = access(frompath)
  183.     if type(data) == "table" then
  184.         fs.makeDir(topath)
  185.         fs.delete(frompath)
  186.     elseif type(data) == "string" then
  187.         local h = fs.open(topath, "wb")
  188.         if h then
  189.             for i = 1, #data do
  190.                 h.write(string.byte(data, i))
  191.             end
  192.             h.close()
  193.         else
  194.             error("File exists")
  195.         end
  196.         fs.delete(frompath)
  197.     else
  198.         error("No matching files")
  199.     end
  200. end
  201.  
  202. function fs.copy(frompath, topath)
  203.     local data = access(frompath)
  204.     if type(data) == "table" then
  205.         fs.makeDir(topath)
  206.     elseif type(data) == "string" then
  207.         local h = fs.open(topath, "wb")
  208.         if h then
  209.             for i = 1, #data do
  210.                 h.write(string.byte(data, i))
  211.             end
  212.             h.close()
  213.         else
  214.             error("File exists")
  215.         end
  216.     else
  217.         error("No matching files")
  218.     end
  219. end
  220.  
  221. fs.combine = _fs.combine
  222.  
  223. function fs.open(path, mode)
  224.     local parts = getParts(path)
  225.     if mode == "r" or mode == "rb" then
  226.         local data = access(path)
  227.         if type(data) ~= "string" then return end
  228.        
  229.         local handle = { }
  230.         local closed = false
  231.         local index = 1
  232.         if mode == "rb" then
  233.             function handle.read()
  234.                 if closed then error("Stream closed") end
  235.                 if index > #data then return end
  236.                 local byte = string.byte(data, index)
  237.                 index = index + 1
  238.                 return byte
  239.             end
  240.         else
  241.             function handle.readLine()
  242.                 if closed then error("Stream closed") end
  243.                 if index > #data then return nil end
  244.                 for i = index, #data do
  245.                     if data:sub(i, i) == "\n" then
  246.                         local str = data:sub(index, i - 1)
  247.                         index = i + 1
  248.                         return str
  249.                     end
  250.                 end
  251.                 local str = data:sub(index, #data)
  252.                 index = #data + 1
  253.                 return str
  254.             end
  255.             function handle.readAll()
  256.                 if closed then error("Stream closed") end
  257.                 if index > #data then return "" end
  258.                 local str = data:sub(index, #data - ((data:sub(#data, #data) == "\n") and 1 or 0))
  259.                 index = #data + 1
  260.                 return str
  261.             end
  262.         end
  263.         function handle.close()
  264.             closed = true
  265.         end
  266.         return handle
  267.     elseif mode == "w" or mode == "wb" or mode == "a" or mode == "ab" then
  268.         if parts[1] == "rom" then
  269.             error("Access Denied")
  270.         end
  271.         if not access(path) then
  272.             if #parts > 1 then
  273.                 local dir = ""
  274.                 for i = 1, #parts - 1 do
  275.                     dir = dir.."/"
  276.                 end
  277.                 if not pcall(fs.makeDir, dir) then return end
  278.             end
  279.         elseif type(access(path)) == "table" then return end
  280.  
  281.         local current = fsTree
  282.         for i = 1, #parts - 1 do
  283.             if type(current[parts[i]]) ~= "table" then return end
  284.             current = current[parts[i]]
  285.         end
  286.         local file = parts[#parts]
  287.  
  288.         local data = {""}
  289.         if current[file] then
  290.             if mode:sub(1, 1) == "w" then
  291.                 current[file] = ""
  292.             else
  293.                 data = current[file]
  294.             end
  295.         else
  296.             current[file] = ""
  297.         end
  298.  
  299.         local handle = { }
  300.         local closed = false
  301.         if mode == "wb" or mode == "ab" then
  302.             function handle.write(byte)
  303.                 if closed then error("Stream closed") end
  304.                 data[#data + 1] = string.char(byte)
  305.             end
  306.         else
  307.             function handle.write(str)
  308.                 if closed then error("Stream closed") end
  309.                 data[#data + 1] = str
  310.             end
  311.             function handle.writeLine(str)
  312.                 if closed then error("Stream closed") end
  313.                 data[#data + 1] = str.."\n"
  314.             end
  315.         end
  316.         function handle.flush()
  317.             current[file] = table.concat(data)
  318.             data = {current[file]}
  319.         end
  320.         function handle.close()
  321.             handle.flush()
  322.             closed = true
  323.         end
  324.         return handle
  325.     else
  326.         error("Unsupported mode")
  327.     end
  328. end
  329.  
  330. function fs.find(wildcard)
  331.     wildcard = getPath(wildcard)
  332.     local paths = { }
  333.    
  334.     local function addPaths(path, dir)
  335.         for i = 1, #dir do
  336.             local p = path.."/"..dir[i]
  337.             local c = access(p)
  338.             paths[#paths + 1] = p:sub(2)
  339.             if type(c) == "table" then
  340.                 addPaths(p, c)
  341.             end
  342.         end
  343.     end
  344.     addPaths("", access(""))
  345.  
  346.     local _, wslashes = wildcard:gsub("%/", "")
  347.     local pattern = wildcard:gsub("%*", "[^/]+")
  348.     local results = { }
  349.     for i = 1, #paths do
  350.         if paths[i]:match(pattern) then
  351.             local __, pslashes = paths[i]:gsub("%/", "")
  352.             if wslashes == pslashes then
  353.                 results[#results + 1] = paths[i]
  354.             end
  355.         end
  356.     end
  357.     return results
  358. end
  359.  
  360. fs.getDir = _fs.getDir
  361.  
  362. function fs.complete(partialname, path, includefiles, includeslashes) -- todo
  363.     local dir = access(path)
  364.     if type(dir) ~= "table" then return { } end
  365.     local completes = { }
  366.     for i = 1, #dir do
  367.         if dir[i]:sub(1, #partialname) == partialname then
  368.             if type(access(path.."/"..dir[i])) ~= "string" or includefiles then
  369.                 if includeslashes then
  370.                     completes[#completes + 1] = dir[i]:sub(#partialname + 1).."/"
  371.                 end
  372.                 completes[#completes + 1] = dir[i]:sub(#partialname + 1)
  373.             end
  374.         end
  375.     end
  376.     return completes
  377. end
  378.  
  379. if ({...})[1] == "-i" then
  380.     local function scan(path)
  381.         local items = _fs.list(path)
  382.         for i = 1, #items do
  383.             if not (path == "" and items[i] == "rom") then
  384.                 local p = path.."/"..items[i]
  385.                 if _fs.isDir(p) then
  386.                     fs.makeDir(p)
  387.                     scan(p)
  388.                 else
  389.                     local ih = _fs.open(p, "rb")
  390.                     if ih then
  391.                         local h = fs.open(p, "wb")
  392.                         local byte = ih.read()
  393.                         while byte do
  394.                             h.write(byte)
  395.                             byte = ih.read()
  396.                         end
  397.                         ih.close()
  398.                         h.close()
  399.                     end
  400.                 end
  401.             end
  402.         end
  403.     end
  404.     scan("")
  405. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement