Created
June 5, 2015 23:30
-
-
Save jaredallard/51fc66786c1ebf618a52 to your computer and use it in GitHub Desktop.
Almost done cext implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
A lightweight ext-like FS implemented in pure lua. | |
Specs: <insert link here> | |
@author Jared Allard <[email protected]> | |
@license MIT | |
@notice uses JSDoc like insource documention. | |
]] | |
-- intial declearation of the FS table. | |
local cext = { | |
["version"] = 001, | |
["date"] = 20150530, | |
["inodeAllocations"] = 500, -- amount of lines to save for inodes untill dynamic. | |
["print"] = function(msg) | |
return nil -- no output | |
end, | |
["fs"] = nil, -- assurance. | |
} | |
-- temporary. | |
-- split a string | |
function string.split(s, delimiter) | |
result = {}; | |
for match in (s..delimiter):gmatch("(.-)"..delimiter) do | |
table.insert(result, match); | |
end | |
return result; | |
end | |
--[[ | |
Create a filesystem. | |
@return {boolean} - success or failure | |
]] | |
cext.createFS = function(this, location, size) | |
-- this.checkArgs(this, size) | |
-- superblockHeader. | |
local superblockHeader = this.version..",0,"..size..",1" | |
local inodeAllocation = "" | |
-- generate whitespace. | |
this.print("generating lines of whitespace.") | |
for i = 1,this.inodeAllocations do | |
inodeAllocation = inodeAllocation.."\n" | |
end | |
local contents = this.inodeAllocations+1 | |
-- remove a stale filesystem. | |
if fs.exists(location) then | |
this.print("removing stale fs") | |
fs.delete(location) | |
end | |
-- open a io file handle and inject the superblockHeader & inodeAllocation ws. | |
this.print("writing fs") | |
local iohandle = io.open(location, "w") | |
iohandle:write(superblockHeader..","..tostring(contents)..inodeAllocation) | |
iohandle:close() | |
this.print("done") | |
-- return true since we probably had no issues. | |
return true | |
end | |
--[[ | |
Open the file system (essentially load it into memory) | |
@return {boolean} - success or fail. | |
]] | |
cext.open = function(this, filesystem) | |
-- give the fs object an initial start. | |
this.fs = { | |
["superblock"] = nil, | |
["data"] = nil, | |
["path"] = nil, | |
} | |
-- load the raw filesystem. | |
local iohandle = fs.open(filesystem, "r") | |
this.fs.superblock = iohandle.readLine() | |
this.fs.data = iohandle.readAll() -- read the data raw. This includes inodes. | |
iohandle.close() | |
-- look at the superblock for the next available inode line. | |
local superblockSplit = string.split(this.fs.superblock, ",") | |
-- assign it to the table. | |
this.fs.superblock = {} | |
this.fs.superblock.version = superblockSplit[1] | |
this.fs.superblock.inodes = superblockSplit[2] | |
this.fs.superblock.size = superblockSplit[3] | |
this.fs.superblock.nextInode = superblockSplit[4] | |
this.fs.superblock.nextContents = superblockSplit[5] | |
-- probably no errors, so set the path. | |
this.fs.path = filesystem | |
this.print('opened cext filesystem version: '..this.fs.superblock.version) | |
-- return true as we probably had no issues. | |
return true | |
end | |
--[[ | |
Close the filesystem. (write to disk) | |
@return {boolean} - success or fail | |
]] | |
cext.close = function(this) | |
local superblock = this.fs.superblock.version..","..this.fs.superblock.inodes.. | |
","..this.fs.superblock.size..","..this.fs.superblock.nextInode..",".. | |
this.fs.superblock.nextContents | |
local data = this.fs.data | |
-- create the final object of the fs. | |
local filesystem = superblock..data | |
local fshandle = fs.open(this.fs.path, "w") | |
fshandle.write(filesystem) | |
fshandle.close() | |
this.print("cext: this.fs.data_table = "..tostring(this.fs.data_table)) | |
return true | |
end | |
--[[ | |
Write to the filesystem | |
@return {boolean} - success or fail, if fail then error message | |
on second param return. | |
]] | |
cext.write = function(this, filename, data) | |
if this.fs == nil then | |
error("fs isn't loaded. load with this:open(fs)") | |
end | |
local fileLocation = fs.getDir(filename) | |
local fileName = fs.getName(filename) | |
-- generate the object. | |
this.print("generating inode for '"..tostring(filename).."'") | |
local inodeObject = fileLocation..","..fileName | |
-- write the filecontents. | |
local nl = string.split(data, "\n") | |
local min = this.fs.superblock.nextContents | |
local max = min | |
for i, v in pairs(nl) do | |
max = max+1 | |
local n = this.fs.superblock.nextContents+(i-1) | |
if i == #nl then | |
this.print("cext: write: i is nl len. call asm.") | |
this:writeToLine(n, v, true) | |
else | |
this:writeToLine(n, v) | |
end | |
end | |
inodeObject = inodeObject..","..min.."-"..max | |
-- print it out for now. | |
this.print(inodeObject) | |
this.print("fs.superblock.nextInode = "..tostring(this.fs.superblock.nextInode)) | |
-- write the new inode to the actual line. | |
this:writeToLine(this.fs.superblock.nextInode, inodeObject, true) | |
-- incrememnt the amount of inodes by 1. | |
this.fs.superblock.nextInode = math.floor(this.fs.superblock.nextInode+1) | |
-- increment the amount of content lines | |
this.fs.superblock.nextContents = max | |
return true | |
end | |
--[[ | |
Write to a line in the filesystem cache. | |
@return {boolean} - success or fail. | |
]] | |
cext.writeToLine = function(this, line, data, asm) | |
-- check if we've already been called. We should sync on asm = true | |
if this.fs.data_table == nil then | |
this.fs.data_table = string.split(this.fs.data, "\n") | |
end | |
-- write to the line, this is a very fragile operation. | |
this.fs.data_table[line] = data | |
if asm == true then | |
this.print("cext: told to assemble the table into a string") | |
-- convert the table into a string. | |
local d = "" | |
for i,v in pairs(this.fs.data_table) do | |
d = d..v.."\n" | |
end | |
-- set the string as the new data object. | |
this.fs.data = tostring(d) | |
-- invalidate the table. | |
this.fs.data_table = nil | |
end | |
-- since we are stil here, we had a successful write. | |
return true | |
end | |
--[[ | |
Read the contents of a file. | |
@return {string} - file contents, or nil on failure. | |
]] | |
cext.read = function(this, file) | |
local inode = this.fs.data:match(file..",[a-z,0-9-]+") | |
if inode == nil then | |
-- doesn't exist. | |
return nil | |
end | |
this.print("got: "..inode) | |
local m = string.split(inode, ",") | |
this.print("contents are on: "..m[2]) | |
return this:readLines(m[2]) | |
end | |
cext.readLines = function(this, linesep) | |
local nl = string.split(this.fs.data, "\n") | |
local m = string.split(linesep, '-') | |
local min = tonumber(m[1]) | |
local max = tonumber(m[2]) | |
local d = "" | |
for i,v in pairs(nl) do | |
if i > min and i < max then | |
d = d..v.."\n" | |
end | |
end | |
if d == "" then | |
return false | |
end | |
return d | |
end | |
-- TESTING | |
fs.delete("test.fs") | |
cext:createFS("test.fs", 1000) | |
cext:open("test.fs") | |
cext:write("nothing", "hacky fix") | |
cext:close() | |
cext:write("ccdocker", fs.open("ccdocker", "r").readAll()) | |
cext:close() | |
-- test file read. | |
cext:read("ccdocker") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment