The alternative system I propose is as follows:
A folder named ".meta" will be present in the root of the drive. Any program may create this folder if it is not present, but no program may delete this folder without explicit instruction to do so by the user (for instance, the user running "rm .meta").
Inside this folder, the folder structure present in the rest of the computer will be mirrored for any metadata present. A file named bar in the folder foo (/foo/bar) would have metadata present at "/.meta/foo/bar". The metadata file will be a valid Lua file declaring a number of values. No values are required to be present, but some values must be in the specified format if they are present. Each value is listed in the table below; an example metadata file follows:
Key: Value:
name string
author string
version string
description string
icon table
timestamp table
type string
The "icon" table would be formatted with each key of the table being the width and height of the icon image as a string, concatenated from width.."x"..height. The value of each would be a file location. The metadata of those files would be used for file type detection, if applicable.
The timestamp table's keys would be any of the following values: created, modified, accessed. The value would be a standard time stamp format to be determined, but likely including in-game date and time in a string.
An example metadata file:
name = "Awesome Image"
author = "oeed"
type = "sketch"
timestamp = {
accessed = "2, 12:45",
modified = "1, 9:32",
created = "1, 9:28",
}
Timestamp values are using an arbitrary format and do not constitute a formal proposal.
Here is an example function to parse a metadata file, given an exact path to the file. As you can see, storing the metadata as both a human-readable file and a valid Lua file has distinct advantages. Note that to maintain human-readability, textutils.serialize is not an option, due to its behavior on pre-1.6 versions of ComputerCraft. This function returns a table, where each key is one of the metadata attributes (name, version, description, etc.) and the values are the values declared in the metadata file:
function parseMeta(metaPath)
if fs.exists(metaPath) then
local handle = fs.open(metaPath, "r")
if handle then
local data = {}
local fn, err = loadstring(handle.readAll())
handle.close()
if fn then
setfenv(fn, data)
local success, err = pcall(fn)
if success then
return data
else
return nil, err
end
else
return nil, err
end
else
return nil, "could not read metadata"
end
else
return nil, "no metadata found"
end
end
Obviously, getting the metadata for a file using the file's path is a simple matter:
function getMetadataForFile(path)
return parseMeta(fs.combine(".meta", path))
end
To build a comprehensive table of metadata for all files on the computer, we simply need another pair of functions. The below functions implement a recursive solution, using a worker function to get all of the metadata for each file in a folder, and another function to correctly initialize the first function.
local function getMetadataForFolder(folderPath, metadata)
if not metadata then metadata = {} end
for _, file in ipairs(fs.list(folderPath)) do
local path = fs.combine(folderPath, file)
if fs.isDir(path) then
getMetadataForFolder(path, metadata)
else
metadata[path] = parseMeta(path)
end
end
return metadata
end
function getAllMetadata()
if fs.exists(".meta") and fs.isDir(".meta") then
return getMetadataForFolder(".meta")
else
return nil, "no metadata available"
end
end
As you can see, the above two functions only iterate the files in the .meta folder to avoid extra file existence checks. If desired, the parseMeta function could be switched out for the getMetadataForFile function and an exception made to ignore the .meta folder when looking for files to check metadata on.
Packed metadata (for file transmission purposes) can be handled by packing the metadata in whatever format is desired and providing an unpacking function at the top of the file. If present, an unpacking function will be preceded by the comment "–@start unpack" and followed by the comment "–@end unpack". This function will be loaded into an environment including all built-in APIs and the current shell, and executed with one parameter: the full path of the file. This will allow the file to write its own metadata file and self-modify to remove the unpacking function if desired.