Advertisement
ROFLCopter64bit

VFS - Virtual Filesystem

Jun 21st, 2014
861
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.16 KB | None | 0 0
  1. vdrives = {} --The global table for mounted images
  2.  
  3. invalidNames = { --this is basically a compatibility hack for other programs
  4.     ".",
  5.     "",
  6. }
  7.  
  8. oldFS = {
  9.     open = fs.open,
  10.     delete = fs.delete,
  11.     makeDir = fs.makeDir,
  12.     list = fs.list,
  13.     exists = fs.exists,
  14.     isDir = fs.isDir,
  15.     getDrive = fs.getDrive,
  16.     move = fs.move,
  17.     copy = fs.copy,
  18.     isReadOnly = fs.isReadOnly,
  19.     combine = fs.combine,
  20.     getDir = fs.getDir,
  21.     getSize = fs.getSize,
  22. }
  23.  
  24. fs.isReadOnly = function(path)
  25.     if isVirtual(file) then -- is virtual
  26.         for dname,drive in pairs(vdrives) do
  27.             for fname,file in pairs(drive.files) do
  28.                 name = "//" .. dname .. "/" .. fname
  29.                 if name == path then
  30.                     return file.isReadOnly
  31.                 end
  32.             end
  33.        
  34.             name = "//" .. dname
  35.             if name == path then
  36.                 return false
  37.             end
  38.         end
  39.         error("File doesn't exist")
  40.     else
  41.         return oldFS.isReadOnly(path)
  42.     end
  43. end
  44.  
  45. fs.open = function(file, mode)
  46.     if isVirtual(file) then -- is virtual
  47.    
  48.         local a = string.find(file:sub(3, -1), "/")
  49.        
  50.         if fs.exists(file) == false or mode:sub(1, 1) == "w" then
  51.             vdrives[file:sub(3, a + 1)].files[file:sub(a + 3, -1)] = {
  52.                 data = '',
  53.                 isReadOnly = false,
  54.                 isDir = false
  55.             }
  56.         end
  57.        
  58.         fobj = { position = 0 }    
  59.         fobj.data = vdrives[file:sub(3, a + 1)].files[file:sub(a + 3, -1)].data --doesn't work when writing
  60.        
  61.         if string.sub(mode, 1, 1) == "r" then
  62.             if string.sub(mode, 2, 2) == "b" then
  63.                 fobj.read = function()
  64.                     fobj.position = fobj.position + 1
  65.                     local x = #fobj.data < realPos and nil or tonumber(fobj.data:sub(fobj.position, fobj.position + 1), 16)
  66.                     fobj.position = fobj.position + 2
  67.                     return x
  68.                 end
  69.             else
  70.                 fobj.readLine = function()
  71.                     if fobj.position > #fobj.data then return nil end
  72.                    
  73.                     local line = ""
  74.                     fobj.position = fobj.position + 1
  75.                     for i = fobj.position, #fobj.data, 2 do
  76.                         local nByte = tonumber(fobj.data:sub(i, i + 1), 16)
  77.                         if nByte == 10 then
  78.                             fobj.position = i + 1
  79.                             return line -- .. "\n"
  80.                         else
  81.                             line = line .. string.char(nByte)
  82.                         end
  83.                         fobj.position = fobj.position + 2
  84.                     end
  85.                     fobj.position = fobj.position + 2
  86.                     return line
  87.                 end
  88.                 fobj.readAll = function()
  89.                     if fobj.position > #fobj.data then return nil end
  90.                    
  91.                     local text = ""
  92.                     fobj.position = fobj.position + 1
  93.                     for i = fobj.position, #fobj.data, 2 do
  94.                         local nByte = tonumber(fobj.data:sub(i, i + 1), 16)
  95.                         text = text .. string.char(nByte)
  96.                     end
  97.                     fobj.position = #fobj.data + 1
  98.                     return text
  99.                 end
  100.                 fobj.readRaw = function()
  101.                     return fobj.data
  102.                 end
  103.             end
  104.            
  105.         elseif (string.sub(mode, 1, 1) == "w") or (string.sub(mode, 1, 1) == "a") then
  106.             if string.sub(mode, 2, 2) == "b" then
  107.                 fobj.write = function(b)
  108.                     vdrives[file:sub(3, a + 1)].files[file:sub(a + 3, #file)].data = vdrives[file:sub(3, a + 1)].files[file:sub(a + 3, #file)].data .. string.format('%02x', b)
  109.                 end
  110.                 fobj.writeRaw = function(w)
  111.                     vdrives[file:sub(3, a + 1)].files[file:sub(a + 3, #file)].data = w
  112.                 end
  113.             else
  114.                 fobj.write = function(s)
  115.                     for i = 1, #s do
  116.                         vdrives[string.sub(file, 3, a + 1)].files[string.sub(file, a + 3, #file)].data = vdrives[string.sub(file, 3, a + 1)].files[string.sub(file, a + 3, #file)].data .. string.format('%02x', string.byte(string.sub(s, i, i)))
  117.                     end
  118.                 end
  119.                 fobj.writeLine = function(s)
  120.                     fobj.write(s .. '\n')
  121.                 end
  122.             end
  123.         end
  124.        
  125.         fobj.close = function()
  126.             --nothing needs to be done, object just needs to be cleared
  127.             fobj = nil
  128.         end
  129.        
  130.         return fobj
  131.     else -- is real
  132.         return oldFS.open(file, mode)
  133.     end
  134. end
  135.  
  136. fs.isDir = function(path)
  137.     if isVirtual(path) then
  138.         for dname,drive in pairs(vdrives) do
  139.        
  140.             name = "//" .. dname
  141.             name2 = "//" .. dname .. "/"
  142.             if name == path or name2 == path then
  143.                 return true
  144.             end
  145.            
  146.             for fname,file in pairs(drive.files) do
  147.                 name = "//" .. dname .. "/" .. fname
  148.                 if name == path then
  149.                     return file.isDir
  150.                 end
  151.                
  152.                 dirname = "//" .. dname .. "/" .. fname .. "/"
  153.                 if dirname == path then
  154.                     return file.isDir
  155.                 end
  156.             end
  157.         end
  158.         error("File doesn't exist")
  159.     else
  160.         return oldFS.isDir(path)
  161.     end
  162. end
  163.  
  164. fs.exists = function(path)
  165.     if isVirtual(path) then
  166.         for dname,drive in pairs(vdrives) do
  167.             for fname,file in pairs(drive.files) do
  168.                 name = "//" .. dname .. "/" .. fname
  169.                 if name == path then
  170.                     return true
  171.                 end
  172.             end
  173.            
  174.             name = "//" .. dname
  175.             name2 = "//" .. dname .. "/"
  176.             if name == path or name2 == path then
  177.                 return true
  178.             end
  179.         end
  180.         return false
  181.     else
  182.         return oldFS.exists(path)
  183.     end
  184. end
  185.  
  186. fs.combine = function(basePath, localPath)
  187.     if isVirtual(localPath) then
  188.         return localPath
  189.     elseif isVirtual(basePath) then
  190.         return basePath .. "/" .. localPath
  191.     else
  192.         return oldFS.combine(basePath, localPath)
  193.     end
  194. end
  195.  
  196. fs.list = function(path)
  197.     if isVirtual(path) then
  198.         tList = {}
  199.        
  200.         for dname,drive in pairs(vdrives) do
  201.             for fname,file in pairs(drive.files) do
  202.                 name = "//" .. dname .. "/" .. fname
  203.                
  204.                 local a, b = string.find(name, path)
  205.                
  206.                 if string.find(name, path) ~= nil then
  207.                     if string.find(string.sub(name, b + 2, -1), "/") == nil and string.sub(name, b + 2, -1) ~= nil and string.gsub(string.sub(name, b + 2, -1), " ", "") ~= "" then --lots of methods to prevent invalid entries
  208.                         table.insert(tList, string.sub(name, b + 2, -1))
  209.                     end
  210.                 end
  211.             end
  212.         end
  213.         return tList
  214.     else
  215.         return oldFS.list(path)
  216.     end
  217. end
  218.  
  219. fs.delete = function(path)
  220.     if isVirtual(path) then
  221.         if fs.isReadOnly(path) == false then
  222.             if fs.isDir(path) then
  223.                 local tList = fs.list(path)
  224.                 if #tList > 0 then
  225.                     for i = 1, #tList do
  226.                         if tList[i] ~= "" and tList[i] ~= nil then
  227.                             fs.delete(path .. "/" .. fs.getName(tList[i]))
  228.                         end
  229.                     end
  230.                 end
  231.             end
  232.             local tryDelete = function()
  233.                 vdrives[getDriveName(path)].files[getFileName(path)] = nil
  234.                 if fs.exists(path) then
  235.                     error("Error deleting " .. path)
  236.                 else
  237.                     return true
  238.                 end
  239.             end
  240.             ok = pcall(tryDelete)
  241.             if ok == false then
  242.                 print("Error deleting " .. path)
  243.             end
  244.         else
  245.             error("Path is read-only")
  246.         end
  247.     else
  248.         return oldFS.delete(path)
  249.     end
  250. end
  251.  
  252. fs.makeDir = function(path)
  253.     if isVirtual(path) then -- is virtual
  254.         vdrives[getDriveName(path)].files[getFileName(path)] = {
  255.             data = '',
  256.             isReadOnly = false,
  257.             isDir = true
  258.         }
  259.     else
  260.         return oldFS.makeDir(path)
  261.     end
  262. end
  263.  
  264. fs.getDrive = function(path)
  265.     if isVirtual(path) then -- is virtual
  266.         return "vfs"
  267.     else
  268.         return oldFS.getDrive(path)
  269.     end
  270. end
  271.  
  272. fs.copy = function(fromPath, toPath)
  273.     if isVirtual(fromPath) or isVirtual(toPath) then
  274.    
  275.         if fs.exists(fs.getDir(toPath)) == false then
  276.             fs.makeDir(fs.getDir(toPath))
  277.         end
  278.        
  279.         if fs.isDir(fromPath) then
  280.             local tList = fs.list(fromPath)
  281.             if #tList > 0 then
  282.                 for i = 1, #tList do
  283.                     if tList[i] ~= "" and tList[i] ~= nil then
  284.                         fs.copy(fromPath .. "/" .. fs.getName(tList[i]), toPath .. "/" .. fs.getName(tList[i]))
  285.                     end
  286.                 end
  287.             end
  288.             if fs.exists(toPath) == false then
  289.                 fs.makeDir(toPath)
  290.             end
  291.         else
  292.            
  293.             if fs.exists(toPath) then
  294.                 error("File already exists")
  295.             elseif fs.exists(fromPath) == false then
  296.                 error("File does not exist")
  297.             end
  298.            
  299.             if isVirtual(fromPath) and isVirtual(toPath) == false then --copying from memory to disk
  300.                 local f = fs.open(toPath, "wb")
  301.                 local r = fs.open(fromPath, 'rb')
  302.                 for b in r.read() do
  303.                     f.write(b)
  304.                 end
  305.                 f.close()
  306.             elseif isVirtual(fromPath) == false and isVirtual(toPath) then --copying from disk to memory
  307.                 vdrives[getDriveName(toPath)].files[getFileName(toPath)] = {
  308.                     data = '',
  309.                     isReadOnly = false,
  310.                     isDir = false
  311.                 }
  312.                 local f = fs.open(toPath, 'wb')
  313.                 local r = fs.open(fromPath, "rb")
  314.                 for b in r.read() do
  315.                     f.write(b)
  316.                 end
  317.                 f.close()
  318.             else --copying from memory to memory
  319.                 vdrives[getDriveName(toPath)].files[getFileName(toPath)] = {
  320.                     data = '',
  321.                     isReadOnly = false,
  322.                     isDir = false
  323.                 }
  324.                 vdrives[getDriveName(toPath)].files[getFileName(toPath)].data = vdrives[getDriveName(fromPath)].files[getFileName(fromPath)].data
  325.             end
  326.         end
  327.     else
  328.         return oldFS.copy(fromPath, toPath) --copying from disk to disk
  329.     end
  330. end
  331.  
  332. fs.move = function(fromPath, toPath)
  333.     fs.copy(fromPath, toPath)
  334.     fs.delete(fromPath)
  335. end
  336.  
  337. fs.getDir = function(path)
  338.     if isVirtual(path) then
  339.         return "//" .. oldFS.getDir(path)
  340.     else
  341.         return oldFS.getDir(path)
  342.     end
  343. end
  344.  
  345. mount = function(image) --add image to vdrives
  346.     if isValidName(image.name) == false then return end
  347.     vdrives[image.name] = image
  348. end
  349.  
  350. unmount = function(name) --remove image from vdrives
  351.     if isValidName(name) == false then return end
  352.     vdrives[name] = nil
  353. end
  354.  
  355. getMountedImage = function(name) --returns a loaded image
  356.     return vdrives[name]
  357. end
  358.  
  359. listMountedImages = function() --returns a table of names of mounted images
  360.     tList = {}
  361.     for dname, drive in pairs(vdrives) do
  362.         table.insert(tList, dname)
  363.     end
  364.     return tList
  365. end
  366.  
  367. createImage = function(_name) --returns a blank image
  368.     return {   
  369.         name = _name,      
  370.         files = {}
  371.     }
  372. end
  373.  
  374. exportImage = function(name) --hdd to image
  375.     if isValidName(name) == false then return end
  376.     image = createImage(name)
  377.    
  378.     local i = 0
  379.     local wildcard = ""
  380.     repeat
  381.         i = 0
  382.         wildcard = wildcard .. "*/"
  383.         t = fs.find(wildcard)
  384.         for k = 1, #t do
  385.             local a, b = string.find(t[k], "rom")
  386.             if a ~= 1 then
  387.                 i = i + 1
  388.                 image.files[t[k]] = {
  389.                     data = '',
  390.                     isDir = false,
  391.                     isReadOnly = false
  392.                 }
  393.                
  394.                 image.files[t[k]].isReadOnly = fs.isReadOnly(t[k])
  395.                 image.files[t[k]].isDir = fs.isDir(t[k])
  396.                
  397.                 if fs.isDir(t[k]) == false then
  398.                     f = fs.open(t[k], "rb")
  399.                     s = 0
  400.                     repeat
  401.                         s = f.read()
  402.                         if s ~= nil then
  403.                             image.files[t[k]].data = image.files[t[k]].data .. string.format('%02x', s)
  404.                         end
  405.                     until s == nil
  406.                 end
  407.             end
  408.         end
  409.     until i == 0
  410.    
  411.     return image
  412. end
  413.  
  414. importImage = function(image, append) --replace hdd with image
  415.     if not append then format() end
  416.     for fname, file in ipairs(image.files) do
  417.         if file.isDir then
  418.             fs.makeDir(fname)
  419.         else
  420.             local f = fs.open(fname, "wb")
  421.             for i = 1, #file.data, 2 do
  422.                 local nByte = tonumber(fobj.data:sub(i, i + 1), 16)
  423.                 f.write(nByte)
  424.             end
  425.         end
  426.     end
  427. end
  428.  
  429. format = function() --delete everything on the HDD
  430.     shell.run("rm *")
  431.    
  432.     --[[ local i = 0
  433.     local wildcard = ""
  434.     repeat
  435.         i = 0
  436.         wildcard = wildcard .. "*/"
  437.         t = fs.find(wildcard)
  438.         for k = 1, #t do
  439.             i = i + 1
  440.             local a, b = string.find(t[k], "rom")
  441.             if a ~= 1 then
  442.                 local tryDelete = function()
  443.                     fs.delete(path)
  444.                     if fs.exists(path) then
  445.                         error("Error deleting " .. path)
  446.                     else
  447.                         return true
  448.                     end
  449.                 end
  450.                 ok = pcall(tryDelete)
  451.                 if ok == false then
  452.                     print("Error deleting " .. path)
  453.                 end
  454.             end
  455.         end
  456.     until i == 0 ]]-- legacy method incase rm * breaks
  457. end
  458.  
  459. isVirtual = function(path)
  460.     --legacy methods
  461.     --return string.find(file, "//") ~= nil - caused error on using rom programs
  462.     --return string.sub(path, 2, 2) == "/" - will allow invalid paths/names
  463.     if path == nil or isValidName(path) == false then return false end
  464.    
  465.     for dname,drive in pairs(vdrives) do
  466.         --explicitly exists
  467.         for fname,file in pairs(drive.files) do
  468.             local name = "//" .. dname .. "/" .. fname
  469.             if name == path then
  470.                 return true
  471.             end
  472.         end
  473.        
  474.         local name = "//" .. dname
  475.         local name2 = "//" .. dname .. "/"
  476.         if name == path or name2 == path then
  477.             return true
  478.         end
  479.         --can exist
  480.         if string.sub(path, 3, #name) == dname then
  481.             return isValidName(string.sub(path, #name + 2, #path))
  482.         end
  483.     end
  484.     return false
  485. end
  486.  
  487. isValidName = function(name)
  488.     for i = 1, #invalidNames do
  489.         if invalidNames[i] == name then
  490.             return false
  491.         end
  492.     end
  493.     return true
  494. end
  495.  
  496. getDriveName = function(path)
  497.     local f = string.sub(path, 3, #path)
  498.     local pos = string.find(f, "/")
  499.     return string.sub(f, 1, pos - 1)
  500. end
  501.  
  502. getFileName = function(path)
  503.     local f = string.sub(path, 3, #path)
  504.     local pos = string.find(f, "/")
  505.     return string.sub(f, pos + 1, #path)
  506. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement