Sewbacca

FSector

Oct 5th, 2016
173
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2.  
  3. MIT License
  4.  
  5. Copyright (c) 2016 Sewbacca
  6.  
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13.  
  14. The above copyright notice and this permission notice shall be included in all
  15. copies or substantial portions of the Software.
  16.  
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. SOFTWARE.
  24.  
  25. --]]
  26.  
  27. -- Vars
  28.  
  29. local FSector = {}
  30.  
  31. -- Shortuct headers
  32.  
  33. local patternToString;
  34.  
  35. -- Shortcuts
  36.  
  37. local string_gsub = string.gsub
  38. patternToString = function (sText)
  39.     return sText:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', function(sMatch) return '%' .. sMatch end)
  40. end
  41.  
  42. -- Install FSector API
  43.  
  44. FSector.create = function (parent, sRootDir)
  45.     -- Error providing
  46.  
  47.     if type(parent) ~= 'table' or type(sRootDir) ~= 'string' then
  48.         error('object parent, string rootDir expected', 2)
  49.     end
  50.  
  51.     sRootDir = parent.combine('/', sRootDir)
  52.    
  53.     if not parent.exists(sRootDir) then
  54.         error('Invalid Path', 2)
  55.     end
  56.  
  57.     -- Setup
  58.  
  59.     local fs = {}
  60.     local tReadOnly = {}
  61.     local tMountedPaths = {}
  62.  
  63.     -- Shortcut headers
  64.  
  65.     local resolveMounted;
  66.     local resolve;
  67.     local find;
  68.  
  69.     -- Shortucts
  70.  
  71.     resolveMounted = function (sResolved, bIsMounted, b)
  72.         if tMountedPaths[sResolved] then
  73.             return bIsMounted and true or resolveMounted(tMountedPaths[sResolved])
  74.         end
  75.         local sResolvedPath = sResolved .. '/'
  76.         for sDestination, sSource in pairs(tMountedPaths) do
  77.             if sResolvedPath:sub(1, #sDestination + 1) == sDestination .. '/' then
  78.                 return bIsMounted and true or resolveMounted(parent.combine(sSource, sResolved:sub(#sDestination + 1, -1)))
  79.             end
  80.         end
  81.         return bIsMounted and false or sResolved
  82.     end
  83.  
  84.     resolve = function (sPath, bRaw)
  85.         if type(sPath) ~= 'string' then
  86.             error('string expected, got ' .. type(sPath), 3)
  87.         end
  88.         local sCombined =  parent.combine(sRootDir, sPath) .. '/'
  89.         local sPrefix = sCombined:sub(1, #sRootDir + 1)
  90.         if sRootDir ~= '' and sPrefix ~= sRootDir .. '/' then
  91.             error('Invalid Path', 3)
  92.         end
  93.         sCombined = sCombined:sub(1, -2)
  94.         return bRaw and sCombined or resolveMounted(sCombined)
  95.     end
  96.  
  97.     find = function (sPos, sFullWildcard)
  98.         -- work in progress
  99.     end
  100.  
  101.     -- Install handle
  102.  
  103.     fs.combine = function (...)
  104.         return parent.combine(...)
  105.     end
  106.  
  107.     fs.complete = function (sPrefix, sDir, ...)
  108.         sDir = resolve(sDir)
  109.         return parent.complete(sPrefix, sDir, ...)
  110.     end
  111.  
  112.     fs.copy = function (sSource, sDestination)
  113.         if fs.isReadOnly(sDestination) then
  114.             error('Access Denied', 2)
  115.         end
  116.         sSource, sDestination = resolve(sSource), resolve(sDestination)
  117.         return parent.copy(sSource, sDestination)
  118.     end
  119.  
  120.     fs.delete = function (sPath)
  121.         if fs.isReadOnly(sPath) then
  122.             error('Access Denied', 2)
  123.         end
  124.  
  125.         if fs.isMounted(sPath, true) then
  126.             fs.dismount(sPath)
  127.             return
  128.         end
  129.  
  130.         sPath = resolve(sPath)
  131.         return parent.delete(sPath)
  132.     end
  133.  
  134.     fs.exists = function (sPath)
  135.         local sPath = resolve(sPath)
  136.         return parent.exists(sPath)
  137.     end
  138.  
  139.     fs.find = function (sWildcard)
  140.         sWildcard = resolve(sWildcard, true)
  141.         local ok, tRes = pcall(parent.find, sWildcard)
  142.         if not ok then
  143.             error(tRes, 2)
  144.         end
  145.  
  146.         for i = 1, #tRes do
  147.             tRes[i] = ('/' .. tRes[i]:sub(#sRootDir + 1, -1)):gsub('//?', '', 1)
  148.         end
  149.  
  150.         -- work in progress
  151.  
  152.         return tRes
  153.     end
  154.  
  155.     fs.getDir = function (...)
  156.         return parent.getDir(...)
  157.     end
  158.  
  159.     fs.getDrive = function (sPath)
  160.         if fs.isReadOnly(sPath) then
  161.             return 'rom'
  162.         end
  163.         sPath = resolve(sPath)
  164.         return parent.getDrive(sPath)
  165.     end
  166.  
  167.     fs.getFreeSpace = function (sPath)
  168.         if fs.isReadOnly(sPath) then
  169.             return 0
  170.         end
  171.         sPath = resolve(sPath)
  172.         return parent.getFreeSpace(sPath)
  173.     end
  174.  
  175.     fs.getName = function (...)
  176.         return parent.getName(...)
  177.     end
  178.  
  179.     fs.getSize = function (sPath)
  180.         sPath = resolve(sPath)
  181.         return parent.getSize(sPath)
  182.     end
  183.  
  184.     fs.isDir = function (sPath)
  185.         sPath = resolve(sPath)
  186.         return parent.isDir(sPath)
  187.     end
  188.  
  189.     fs.isReadOnly = function (sPath)
  190.         sPath = resolve(sPath)
  191.         local tmpPath = sPath .. '/'
  192.         for sReadOnly in pairs(tReadOnly) do
  193.             if tmpPath:sub(1, #sReadOnly + 1) == sReadOnly .. '/' then
  194.                 return true
  195.             end
  196.         end
  197.         return parent.isReadOnly(sPath)
  198.     end
  199.  
  200.     fs.setReadOnly = function (sPath, bReadOnly)
  201.         sPath = resolve(sPath)
  202.         bReadOnly = bReadOnly and true or false
  203.         tReadOnly[sPath] = parent.isReadOnly(sPath) or bReadOnly and true or nil
  204.     end
  205.  
  206.     fs.list = function (sDir)
  207.         sDir = resolve(sDir)
  208.         local ok, tRes = pcall(parent.list, sDir)
  209.         if not ok then
  210.             error(tRes, 2)
  211.         end
  212.         for sMounted in pairs(tMountedPaths) do
  213.             if parent.getDir(sMounted) == sDir then
  214.                 tRes[#tRes + 1] = parent.getName(sMounted)
  215.             end
  216.         end
  217.         table.sort(tRes)
  218.         return tRes
  219.     end
  220.  
  221.     fs.makeDir = function (sPath)
  222.         sPath = resolve(sPath)
  223.         return parent.makeDir(sPath)
  224.     end
  225.  
  226.     fs.mount = function (sSource, sDestination)
  227.         sSource, sDestination = resolve(sSource), resolve(sDestination)
  228.         if not parent.exists(sSource) or parent.exists(sDestination) then
  229.             return false
  230.         end
  231.         tMountedPaths[sDestination] = sSource
  232.         return true
  233.     end
  234.  
  235.     fs.dismount = function (sPath)
  236.         sPath = resolve(sPath, true)
  237.         tMountedPaths[sPath] = nil
  238.     end
  239.  
  240.     fs.isMounted = function (sPath, bNotRaw)
  241.         sPath = resolve(sPath, true)
  242.         if not bNotRaw then
  243.             return resolveMounted(sPath, true)
  244.         end
  245.         return tMountedPaths[sPath] and true or false
  246.     end
  247.  
  248.     fs.move = function (sSource, sDestination)
  249.         resolve(sSource)
  250.         resolve(sDestination)
  251.         if fs.isReadOnly(sSource) or fs.isReadOnly(sDestination) or fs.isMounted(sSource) or fs.isMounted(sDestination) then
  252.             error('Access Denied', 2)
  253.         end
  254.  
  255.         sSource, sDestination = resolve(sSource), resolve(sDestination)
  256.         return parent.move(sSource, sDestination)
  257.     end
  258.  
  259.     fs.open = function (sPath, sMode)
  260.         if fs.isReadOnly(sPath) and sMode:match 'a' and sMode:match 'w' then
  261.             return nil
  262.         end
  263.         sPath = resolve(sPath)
  264.         return parent.open(sPath, sMode)
  265.     end
  266.  
  267.     -- Return handle
  268.  
  269.     return fs
  270. end
  271.  
  272. -- Add redirection
  273. do
  274.     -- Code taken from rom/apis/term and modified by Sewbacca
  275.     local native = (fs.native and fs.native()) or nil
  276.     if not native then
  277.         native = {}
  278.         for key, value in pairs(fs) do
  279.             native[key] = value
  280.         end
  281.        
  282.         for key in pairs(native) do
  283.             fs[key] = nil
  284.         end
  285.     end
  286.  
  287.     local redirectTarget = native
  288.  
  289.     local function wrap(_sFunction)
  290.         return function(...)
  291.             return redirectTarget[ _sFunction ](...)
  292.         end
  293.     end
  294.  
  295.     fs.redirect = function(target)
  296.         if target == nil or type(target) ~= 'table' then
  297.             error('Invalid redirect target', 2)
  298.         end
  299.         if target == fs then
  300.             error('fs is not a recommended redirect target, try fs.current() instead', 2)
  301.         end
  302.         for k, v in pairs(native) do
  303.             if type(k) == 'string' and type(v) == 'function' then
  304.                 if type(target[k]) ~= 'function' then
  305.                     target[k] = function ()
  306.                         error('Redirect object is missing method '..k..'.', 2)
  307.                     end
  308.                 end
  309.             end
  310.         end
  311.         local oldRedirectTarget = redirectTarget
  312.         redirectTarget = target
  313.         return oldRedirectTarget
  314.     end
  315.  
  316.     fs.current = function ()
  317.         return redirectTarget
  318.     end
  319.  
  320.     fs.native = function ()
  321.         -- NOTE: please don't use this function unless you have to.
  322.         -- If you're running in a redirected or multitasked enviorment, fs.native() will NOT be
  323.         -- the current fs when your program starts up. It is far better to use fs.current()
  324.         return native
  325.     end
  326.  
  327.     for k, v in pairs(native) do
  328.         if type(k) == 'string' and type(v) == 'function' then
  329.             if fs[k] == nil then
  330.                 fs[k] = wrap(k)
  331.             end
  332.         end
  333.     end
  334. end
  335.  
  336. -- End adding redirection
  337.  
  338. -- Return API
  339.  
  340. return FSector
  341.  
  342. -- End
RAW Paste Data