abstract type 特殊结构 end
mutable struct 文件
par::Union{特殊结构,Nothing}
name::String
content::String
end
mutable struct 目录 <: 特殊结构
par::Union{目录,Nothing}
name::String
files::Dict{String,文件}
dirs::Dict{String,目录}
end
目录(par::Union{目录,Nothing}, name::String) = 目录(par, name, Dict{String,文件}(), Dict{String,目录}())
mutable struct 文件系统
root::目录
current::目录
end
function 文件系统()
rt = 目录(nothing, "")
cu = rt
return 文件系统(rt, cu)
end
function getpath(dir::目录; full::Bool=false, relative::目录=dir)
if full
s = dir.name
isnothing(dir.par) && return "/"
t = dir
while true
t = t.par
isnothing(t.par) && return "/$s"
s = "$(t.name)/$s"
end
else
s = dir.name
t = dir
while true
t = t.par
if t === nothing
return "/$s"
elseif t == relative
return s
end
s = "$(t.name)/$s"
end
end
end
function getdir(dir::目录, path::Vector{T}) where {T<:AbstractString}
res = dir
for i in path
if i == ".."
if res !== nothing
res = res.par
end
elseif i != "."
if haskey(res.dirs, i)
res = @inbounds res.dirs[i]
else
throw("未在$(getpath(res))找到下一级目录")
end
end
end
return res
end
function getdir(fs::文件系统, path::AbstractString)
v = splitpath(path)
if isempty(v)
throw("路径不能为空")
end
d = fs.current
if v[1] == "/"
d = fs.root
popfirst!(v)
end
return getdir(d, v)
end
function getpardir(fs::文件系统, path::AbstractString)::Pair
v = splitpath(path)
if isempty(v)
throw("路径不能为空")
end
d = fs.current
if v[1] == "/"
d = fs.root
popfirst!(v)
if isempty(v)
throw("路径不能为空")
end
end
last = pop!(v)
return Pair(getdir(d, v), last)
end
function getfile(fs::文件系统, path::AbstractString)
v = splitpath(path)
if isempty(v)
throw("路径不能为空")
end
fname = pop!(v)
d = fs.current
if v[1] == "/"
d = fs.root
popfirst!(v)
end
dir = getdir(d, v)
if haskey(dir.files, fname)
return @inbounds dir.files[fname]
else
throw("未找到该文件")
end
end
_pwd(fs::文件系统) = getpath(fs.current; full=true)
function _ls(fs::文件系统, target::目录=fs.current)
for i in target.dirs
println(i.first, "/")
end
for i in target.files
println(i.first)
end
end
function _cd(fs::文件系统, path::AbstractString)
fs.current = getdir(fs, path)
end
function _mkdir(fs::文件系统, path::AbstractString; force::Bool=false)
pair = getpardir(fs, path)
dir = pair.first
name = pair.second
if force
dir.dirs[name] = 目录(dir, name)
return
end
if haskey(dir.dirs, name)
throw("同名目录已存在")
elseif haskey(dir.files, name)
throw("同名文件已存在")
else
dir.dirs[name] = 目录(dir, name)
end
end
function _rmdir(fs::文件系统, path::AbstractString)
pair = getpardir(fs, path)
dir = pair.first
name = pair.second
q = fs.current
while q !== nothing
if q == dir
throw("删除的目录不能包含当前目录")
end
q = q.par
end
delete!(dir.dirs, name)
end
function _rm(fs::文件系统, path::AbstractString)
(dir, name) = getpardir(fs, path)
if haskey(dir.dirs, name)
delete!(dir.dirs, name)
elseif haskey(dir.files, name)
delete!(dir.files, name)
else
throw("未找到该资源")
end
end
function _cp(fs::文件系统, from::AbstractString, to::AbstractString; force::Bool=false)
(dir, name) = getpardir(fs, from)
if haskey(dir.dirs, name)
dirto = getdir(fs, to)
ori = @inbounds(dir.dirs[name])
if !force
haskey(dirto.dirs, name) ? throw("同名目录已存在") :
haskey(dirto.files, name) ? throw("同名文件已存在") : nothing
end
dirto.dirs[name] = 目录(dirto, name, deepcopy(ori.files), deepcopy(ori.dirs))
elseif haskey(dir.files, name)
dirto = getdir(fs, to)
content = @inbounds(dir.files[name].content)
if !force
haskey(dirto.dirs, name) ? throw("同名目录已存在") :
haskey(dirto.files, name) ? throw("同名文件已存在") : nothing
end
dirto.files[name] = 文件(dirto, deepcopy(name), deepcopy(content))
else
throw("未找到该资源")
end
end
function _mv(fs::文件系统, from::AbstractString, to::AbstractString; force::Bool=false)
(dir, name) = getpardir(fs, from)
if haskey(dir.dirs, name)
dirto = getdir(fs, to)
ori = @inbounds(dir.dirs[name])
if !force
haskey(dirto.dirs, name) ? throw("同名目录已存在") :
haskey(dirto.files, name) ? throw("同名文件已存在") : nothing
end
dirto.dirs[name] = 目录(dirto, name, ori.files, ori.dirs)
delete!(dir.dirs, name)
elseif haskey(dir.files, name)
dirto = getdir(fs, to)
content = @inbounds(dir.files[name].content)
if !force
haskey(dirto.dirs, name) ? throw("同名目录已存在") :
haskey(dirto.files, name) ? throw("同名文件已存在") : nothing
end
dirto.files[name] = 文件(dirto, name, content)
delete!(dir.files, name)
else
throw("未找到该资源")
end
end
const simdata = Dict{String,Tuple{UnitRange,UInt8,Symbol}}(
# "sim"=>(1:1,0x7,"")
"pwd" => (0:0, 0x5, :pwd),
"chdir" => (0:0, 0x2, :pwd),
"ls" => (0:1, 0x1, :ls),
"dir" => (0:1, 0x2, :ls),
"readdir" => (0:1, 0x4, :ls),
"cd" => (1:1, 0x7, :cd),
"mkdir" => (1:1, 0x7, :mkdir),
"md" => (1:1, 0x2, :mkdir),
"rmdir" => (1:1, 0x3, :rmdir),
"rm" => (1:1, 0x5, :rm),
"del" => (1:1, 0x2, :rm),
"cp" => (2:2, 0x5, :cp),
"copy" => (2:2, 0x2, :cp),
"mv" => (2:2, 0x7, :mv),
)
function init()
fs = 文件系统()
_mkdir(fs, "home")
_cd(fs, "home")
fs.current.files["hello.txt"] = 文件(fs.current, "hello.txt", "你好")
sim = 0x0
while true
print("vfs> ")
s = readline()
try
v = split(s)
if isempty(v)
continue
end
com = ""
if v[1] == "sim"
sim = v[2] == "unix" ? 0x0 :
v[2] == "windows" ? 0x1 :
v[2] == "julia" ? 0x2 :
printstyled("不支持的模拟对象"; color=:light_yellow)
println()
continue
elseif v[1] == "quit"
return
else
name = String(v[1])
if !haskey(simdata, name)
throw("不支持的命令")
end
data = @inbounds simdata[name]
vl = length(v) - 1
if !in(vl, data[1])
throw("错误的参数个数")
end
if data[2] >> sim & 0x1 != 0x1
throw("该环境不支持该命令")
end
com = data[3]
end
com == :pwd ? println(_pwd(fs)) :
com == :ls ? _ls(fs, vl == 1 ? getdir(fs, v[2]) : fs.current) :
com == :cd ? _cd(fs, v[2]) :
com == :mkdir ? _mkdir(fs, v[2]) :
com == :rmdir ? _rmdir(fs, v[2]) :
com == :rm ? _rm(fs, v[2]) :
com == :cp ? _cp(fs, v[2], v[3]) :
com == :mv ? _mv(fs, v[2], v[3]) :
throw("程序出错")
catch er
if isa(er, String)
printstyled(er; color=:light_red)
println()
else
throw(er)
end
end
println()
end
end
println("""
当前只支持命令格式,不支持额外参数
使用 "sim 目标" 切换模拟环境
""")