#1
Posted 03 September 2016 - 02:23 PM
#3
Posted 03 September 2016 - 03:07 PM
local oldFs = fs
local oldOs = os
fs.open = function(file,method)
if method == 'w' and file == 'your_read_only_file_here' then
error('File is read only!')
else
return oldFs.open(file,method)
end
end
os.run = function(env,path,...)
local args = {...}
env.fs = fs
env.os = os
oldOs.run(env,path,...)
end
Note: I haven't tested this
#4
Posted 03 September 2016 - 05:55 PM
You might want to normalise the path too, as you could get around that by opening './myfile.txt' in write mode to write to 'myfile.txt' (even if you test if it's 'myfile.txt').
Shallow copy code:
local oldFs = {}
for k, v in pairs( fs ) do
oldFs[k] = v
end
Metatable code:
local oldFs = setmetatable( {}, { __index = fs } )
Edit: ignore the metatable solution, it won't work. You're changing the 'fs' table rather than creating a new, modified table and using that. Because of this, you don't even need to modify os.run(). You could even get away with just keeping a copy of the old 'fs.open()' rather than the whole 'fs' table.
Edit 2: I may as well post the code for what I mean...
local function normalise( path )
return path
:gsub( "//+", "/" ) --# remove multiple slashes
:gsub( "/%./", "/" ) --# remove /./ (has no effect on path)
:gsub( "^%./", "" ) --# remove ./ at start (same as above)
:gsub( "(/?)[^/]+/%.%./", "%1" ) --# remove /X/../
:gsub( "(/?)[^/]+/%.%.$", "%1" ) --# remove /X/.. at end
:gsub( "^%.%./", "" ) --# remove ../ at start
:gsub( "^[^/]+/%.%./", "/" ) --# remove X/.. at start
:gsub( "^/", "" ):gsub( "/$", "" ) --# remove trailing slashes
end
local oldOpen = fs.open
local blacklist = {
["my/readonly/path"] = true;
}
function fs.open( path, mode )
if mode ~= "r" and mode ~= "rb" and blacklist[normalise( path )] then
return error( "attempt to open read-only file in '" .. mode .. "' mode" )
else
return oldOpen( path, mode )
end
end
Edited by Exerro, 03 September 2016 - 06:07 PM.
#5
Posted 03 September 2016 - 08:35 PM
Exerro, on 03 September 2016 - 05:55 PM, said:
You might want to normalise the path too, as you could get around that by opening './myfile.txt' in write mode to write to 'myfile.txt' (even if you test if it's 'myfile.txt').
Shallow copy code:
local oldFs = {}
for k, v in pairs( fs ) do
oldFs[k] = v
end
Metatable code:
local oldFs = setmetatable( {}, { __index = fs } )
Edit: ignore the metatable solution, it won't work. You're changing the 'fs' table rather than creating a new, modified table and using that. Because of this, you don't even need to modify os.run(). You could even get away with just keeping a copy of the old 'fs.open()' rather than the whole 'fs' table.
Edit 2: I may as well post the code for what I mean...
local function normalise( path )
return path
:gsub( "//+", "/" ) --# remove multiple slashes
:gsub( "/%./", "/" ) --# remove /./ (has no effect on path)
:gsub( "^%./", "" ) --# remove ./ at start (same as above)
:gsub( "(/?)[^/]+/%.%./", "%1" ) --# remove /X/../
:gsub( "(/?)[^/]+/%.%.$", "%1" ) --# remove /X/.. at end
:gsub( "^%.%./", "" ) --# remove ../ at start
:gsub( "^[^/]+/%.%./", "/" ) --# remove X/.. at start
:gsub( "^/", "" ):gsub( "/$", "" ) --# remove trailing slashes
end
local oldOpen = fs.open
local blacklist = {
["my/readonly/path"] = true;
}
function fs.open( path, mode )
if mode ~= "r" and mode ~= "rb" and blacklist[normalise( path )] then
return error( "attempt to open read-only file in '" .. mode .. "' mode" )
else
return oldOpen( path, mode )
end
end
can't you just let "shell.resolve" handle the "normalizing"?
#6
Posted 04 September 2016 - 09:06 AM
Exerro, on 03 September 2016 - 05:55 PM, said:
local function normalise( path ) return path :gsub( "//+", "/" ) --# remove multiple slashes :gsub( "/%./", "/" ) --# remove /./ (has no effect on path) :gsub( "^%./", "" ) --# remove ./ at start (same as above) :gsub( "(/?)[^/]+/%.%./", "%1" ) --# remove /X/../ :gsub( "(/?)[^/]+/%.%.$", "%1" ) --# remove /X/.. at end :gsub( "^%.%./", "" ) --# remove ../ at start :gsub( "^[^/]+/%.%./", "/" ) --# remove X/.. at start :gsub( "^/", "" ):gsub( "/$", "" ) --# remove trailing slashes end
H4X0RZ, on 03 September 2016 - 08:35 PM, said:
shell.resolve, resolves the path from the current directory.
For example:
current directory: rom
path: rom/../rom/apis
result: rom/rom/apis
local sPath = shell.resolve('rom/../rom/apis') --> rom/rom/apis
fs.combine would give the excepted result:
current directroy: rom
path: rom/../rom/apis
result: rom/apis
local sPath = fs.combine('/', 'rom/../rom/apis') -- rom/apis
-- example resolve function:
local resolve = function(sPath)
return fs.combine('/', sPath)
end
Edited by Sewbacca, 04 September 2016 - 09:08 AM.
#7
Posted 04 September 2016 - 11:26 AM
--# The files that you'd like to be read-only
local paths = {
["startup"] = true;
}
--# Create a backup of the fs table
local _fs = fs
--# Override the function
fs.isReadOnly = function( sPath )
if paths[sPath] then
return true --# If the path matches one of the paths in the table it will return true
else
return _fs.isReadOnly( sPath ) --# If it doesn't then let the native function handle it
end
end
#8
Posted 04 September 2016 - 11:30 AM
TheOddByte, on 04 September 2016 - 11:26 AM, said:
--# The files that you'd like to be read-only
local paths = {
["startup"] = true;
}
--# Create a backup of the fs table
local _fs = fs
--# Override the function
fs.isReadOnly = function( sPath )
if paths[sPath] then
return true --# If the path matches one of the paths in the table it will return true
else
return _fs.isReadOnly( sPath ) --# If it doesn't then let the native function handle it
end
end
Just want to point it out that if you use this, you need to normalize the path, otherwise editing /rom/../startup will probably work.
#9
Posted 05 September 2016 - 07:14 PM
TheOddByte, on 04 September 2016 - 11:26 AM, said:
--# The files that you'd like to be read-only
local paths = {
["startup"] = true;
}
--# Create a backup of the fs table
local _fs = fs
--# Override the function
fs.isReadOnly = function( sPath )
if paths[sPath] then
return true --# If the path matches one of the paths in the table it will return true
else
return _fs.isReadOnly( sPath ) --# If it doesn't then let the native function handle it
end
end
Admicos, on 04 September 2016 - 11:30 AM, said:
It doesn't work correctly. Ignoring the point, that the backup _fs == fs (because they are the same objects) --> true, just edit or paint or other programs who uses fs.isReadOnly() would follow your rules, but fs.open() doesn't use fs.isReadOnly(),
so everyone, who don't take care of fs.isReadOnly() can edit the startup with fs.open(). If you want to prevent writing on a file, try this code:
local tReadOnly = {
'^startup' -- a pattern, working for all strings, containing startup at the start of the string
}
local native_fs = {}
for key, value in pairs(fs) do
native_fs[key] = value -- copying all functions of fs into a new table
end
local isReadOnly = function (sPath) -- modulate the program for a better handling
for i = 1, #tReadOnly do
if sPath:match(tReadOnly[i]) then
return true
end
end
return false
end
fs.isReadOnly = function (sPath) -- For programs who take care of fs.isReadOnly()
return isReadOnly(sPath) and native_fs.isReadOnly(sPath)
end
fs.open = function (sPath, sMode)
if sMode:match('w') or sMode:match('a') and isReadOnly(sPath) then
return nil -- return nil, like the native fs, if the file is read only
end
return native_fs.open(sPath, sMode)
end
-- Note that you have to add fs.delete() and fs.move() here here
(Note, the Code is untested)
Edited by Sewbacca, 05 September 2016 - 07:18 PM.
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users











