Files
cell/cellfs.cm
2026-02-20 15:33:46 -06:00

474 lines
11 KiB
Plaintext

var cellfs = {}
var fd = use('fd')
var miniz = use('miniz')
var qop = use('qop')
var wildstar = use('wildstar')
var mounts = []
var writepath = "."
function normalize_path(path) {
if (!path) return ""
return replace(path, /^\/+|\/+$/, "")
}
function mount_exists(mount, path) {
var result = false
var full_path = null
var st = null
var _check = null
if (mount.type == 'zip') {
_check = function() {
mount.handle.mod(path)
result = true
} disruption {}
_check()
} else if (mount.type == 'qop') {
_check = function() {
result = mount.handle.stat(path) != null
} disruption {}
_check()
} else {
full_path = fd.join_paths(mount.source, path)
_check = function() {
st = fd.stat(full_path)
result = st.isFile || st.isDirectory
} disruption {}
_check()
}
return result
}
function is_directory(path) {
var res = resolve(path)
var mount = res.mount
var result = false
var full_path = null
var st = null
var _check = null
if (mount.type == 'zip') {
_check = function() {
result = mount.handle.is_directory(path)
} disruption {}
_check()
} else if (mount.type == 'qop') {
_check = function() {
result = mount.handle.is_directory(path)
} disruption {}
_check()
} else {
full_path = fd.join_paths(mount.source, path)
_check = function() {
st = fd.stat(full_path)
result = st.isDirectory
} disruption {}
_check()
}
return result
}
function resolve(path, must_exist) {
var idx = null
var mount_name = ""
var rel_path = ""
var mount = null
var found_mount = null
var npath = normalize_path(path)
if (starts_with(npath, "@")) {
idx = search(npath, "/")
if (idx == null) {
mount_name = text(npath, 1)
rel_path = ""
} else {
mount_name = text(npath, 1, idx)
rel_path = text(npath, idx + 1)
}
arrfor(mounts, function(m) {
if (m.name == mount_name) {
mount = m
return true
}
}, false, true)
if (!mount) {
log.error("Unknown mount point: @" + mount_name); disrupt
}
return { mount: mount, path: rel_path }
}
arrfor(mounts, function(m) {
if (mount_exists(m, npath)) {
found_mount = { mount: m, path: npath }
return true
}
}, false, true)
if (found_mount) {
return found_mount
}
if (must_exist) {
log.error("File not found in any mount: " + npath); disrupt
}
}
function mount(source, name) {
var st = fd.stat(source)
var blob = null
var qop_archive = null
var zip = null
var _try_qop = null
var mount_info = {
source: source,
name: name || null,
type: 'fs',
handle: null,
zip_blob: null
}
if (st.isDirectory) {
mount_info.type = 'fs'
} else if (st.isFile) {
blob = fd.slurp(source)
qop_archive = null
_try_qop = function() {
qop_archive = qop.open(blob)
} disruption {}
_try_qop()
if (qop_archive) {
mount_info.type = 'qop'
mount_info.handle = qop_archive
mount_info.zip_blob = blob
} else {
zip = miniz.read(blob)
if (!is_object(zip) || !is_function(zip.count)) {
log.error("Invalid archive file (not zip or qop): " + source); disrupt
}
mount_info.type = 'zip'
mount_info.handle = zip
mount_info.zip_blob = blob
}
} else {
log.error("Unsupported mount source type: " + source); disrupt
}
push(mounts, mount_info)
}
function unmount(name_or_source) {
mounts = filter(mounts, function(m) {
return m.name != name_or_source && m.source != name_or_source
})
}
function slurp(path) {
var res = resolve(path, true)
var data = null
var full_path = null
if (!res) { log.error("File not found: " + path); disrupt }
if (res.mount.type == 'zip') {
return res.mount.handle.slurp(res.path)
} else if (res.mount.type == 'qop') {
data = res.mount.handle.read(res.path)
if (!data) { log.error("File not found in qop: " + path); disrupt }
return data
} else {
full_path = fd.join_paths(res.mount.source, res.path)
return fd.slurp(full_path)
}
}
function slurpwrite(path, data) {
var full_path = writepath + "/" + path
var f = fd.open(full_path, 'w')
fd.write(f, data)
fd.close(f)
}
function exists(path) {
var res = resolve(path, false)
if (starts_with(path, "@")) {
return mount_exists(res.mount, res.path)
}
return res != null
}
function stat(path) {
var res = resolve(path, true)
var mod = null
var s = null
var full_path = null
if (!res) { log.error("File not found: " + path); disrupt }
if (res.mount.type == 'zip') {
mod = res.mount.handle.mod(res.path)
return {
filesize: 0,
modtime: mod * 1000,
isDirectory: false
}
} else if (res.mount.type == 'qop') {
s = res.mount.handle.stat(res.path)
if (!s) { log.error("File not found in qop: " + path); disrupt }
return {
filesize: s.size,
modtime: s.modtime,
isDirectory: s.isDirectory
}
} else {
full_path = fd.join_paths(res.mount.source, res.path)
s = fd.stat(full_path)
return {
filesize: s.size,
modtime: s.mtime,
isDirectory: s.isDirectory
}
}
}
function searchpath() {
return array(mounts)
}
function mount_package(name) {
if (name == null) {
mount('.', null)
return
}
var shop = use('internal/shop')
var dir = shop.get_package_dir(name)
if (!dir) {
log.error("Package not found: " + name); disrupt
}
mount(dir, name)
}
function match(str, pattern) {
return wildstar.match(pattern, str, wildstar.WM_PATHNAME | wildstar.WM_PERIOD | wildstar.WM_WILDSTAR)
}
function rm(path) {
var res = resolve(path, true)
var full_path = null
var st = null
if (res.mount.type != 'fs') { log.error("Cannot delete from non-fs mount"); disrupt }
full_path = fd.join_paths(res.mount.source, res.path)
st = fd.stat(full_path)
if (st.isDirectory) fd.rmdir(full_path)
else fd.unlink(full_path)
}
function mkdir(path) {
var full = fd.join_paths(writepath, path)
fd.mkdir(full)
}
function set_writepath(path) {
writepath = path
}
function basedir() {
return fd.getcwd()
}
function prefdir(org, app) {
return "./"
}
function realdir(path) {
var res = resolve(path, false)
if (!res) return null
return fd.join_paths(res.mount.source, res.path)
}
function enumerate(_path, recurse) {
var path = _path == null ? "" : _path
var res = resolve(path, true)
var results = []
var full = null
var st = null
var all = null
var prefix = null
var prefix_len = null
var seen = null
function visit(curr_full, rel_prefix) {
var list = fd.readdir(curr_full)
if (!list) return
arrfor(list, function(item) {
var item_rel = rel_prefix ? rel_prefix + "/" + item : item
var child_st = null
push(results, item_rel)
if (recurse) {
child_st = fd.stat(fd.join_paths(curr_full, item))
if (child_st.isDirectory) {
visit(fd.join_paths(curr_full, item), item_rel)
}
}
})
}
if (res.mount.type == 'fs') {
full = fd.join_paths(res.mount.source, res.path)
st = fd.stat(full)
if (st && st.isDirectory) {
visit(full, "")
}
} else if (res.mount.type == 'qop') {
all = res.mount.handle.list()
prefix = res.path ? res.path + "/" : ""
prefix_len = length(prefix)
seen = {}
arrfor(all, function(p) {
var rel = null
var slash = null
if (starts_with(p, prefix)) {
rel = text(p, prefix_len)
if (length(rel) == 0) return
if (!recurse) {
slash = search(rel, '/')
if (slash != null) {
rel = text(rel, 0, slash)
}
}
if (!seen[rel]) {
seen[rel] = true
push(results, rel)
}
}
})
}
return results
}
function globfs(globs, _dir) {
var dir = _dir == null ? "" : _dir
var res = resolve(dir, true)
var results = []
var full = null
var st = null
var all = null
var prefix = null
var prefix_len = null
function check_neg(path) {
var result = false
arrfor(globs, function(g) {
if (starts_with(g, "!") && wildstar.match(text(g, 1), path, wildstar.WM_WILDSTAR)) {
result = true
return true
}
}, false, true)
return result
}
function check_pos(path) {
var result = false
arrfor(globs, function(g) {
if (!starts_with(g, "!") && wildstar.match(g, path, wildstar.WM_WILDSTAR)) {
result = true
return true
}
}, false, true)
return result
}
function visit(curr_full, rel_prefix) {
if (rel_prefix && check_neg(rel_prefix)) return
var list = fd.readdir(curr_full)
if (!list) return
arrfor(list, function(item) {
var item_rel = rel_prefix ? rel_prefix + "/" + item : item
var child_full = fd.join_paths(curr_full, item)
var child_st = fd.stat(child_full)
if (child_st.isDirectory) {
if (!check_neg(item_rel)) {
visit(child_full, item_rel)
}
} else {
if (!check_neg(item_rel) && check_pos(item_rel)) {
push(results, item_rel)
}
}
})
}
if (res.mount.type == 'fs') {
full = fd.join_paths(res.mount.source, res.path)
st = fd.stat(full)
if (st && st.isDirectory) {
visit(full, "")
}
} else if (res.mount.type == 'qop') {
all = res.mount.handle.list()
prefix = res.path ? res.path + "/" : ""
prefix_len = length(prefix)
arrfor(all, function(p) {
var rel = null
if (starts_with(p, prefix)) {
rel = text(p, prefix_len)
if (length(rel) == 0) return
if (!check_neg(rel) && check_pos(rel)) {
push(results, rel)
}
}
})
}
return results
}
cellfs.mount = mount
cellfs.mount_package = mount_package
cellfs.unmount = unmount
cellfs.slurp = slurp
cellfs.slurpwrite = slurpwrite
cellfs.exists = exists
cellfs.is_directory = is_directory
cellfs.stat = stat
cellfs.searchpath = searchpath
cellfs.match = match
cellfs.enumerate = enumerate
cellfs.globfs = globfs
cellfs.rm = rm
cellfs.mkdir = mkdir
cellfs.writepath = set_writepath
cellfs.basedir = basedir
cellfs.prefdir = prefdir
cellfs.realdir = realdir
cellfs.mount('.')
return cellfs