This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
darkrising's profile picture

[Question] Virtual Directory / Files

Started by darkrising, 14 May 2013 - 12:02 PM
darkrising #1
Posted 14 May 2013 - 02:02 PM
Hello, I'm working on a remote login type program which sends the users directory on the server computer to the client computer as one big table, the problem I'm facing is if the client computer is switched off before it can clear the files and another user comes along and logs in they will find the previous users files just sitting there. I could do a clean on startup type thing but I'm wondering if there is a way I can fool the computer into thinking that a table is a bunch of files (virtual directory in a sense) but still keep the editing and running of the programs intact.

Any suggestions are much appreciated :P/>
BlankTitle #2
Posted 14 May 2013 - 07:16 PM
I'm not the best with lua, but doing a clear at startup is quick and gets the job done. One thing I would recommend is adding this after you receive the table.

function clearscreen()
term.clear()
end
while true do
print ("Press Q to erase data")
local event, param = os.pullEvent("char")
if param == "Q" then
clearscreen()
else
sleep(1)
end
end

This should wait for your keystroke of "Q" and then clear your computer, and if you enter the wrong key, return you back to the start of this code so you can still view your tables. Hope this works for you!
Grim Reaper #3
Posted 14 May 2013 - 09:01 PM
In my opinion, the best way to go about this is to just clean out the previous user's files, but if you really don't want to do this you could modify the 'fs' API to catch any kind of references to a file or directory in your table and cause the function to treat your table like a file or directory.

I would write you a code example, but I don't know how your virtual file system using a table would work with files in terms of contents, etc.
KaoS #4
Posted 15 May 2013 - 03:03 AM
please send us an example table of files so we can see what it would look like, then we can give you examples
darkrising #5
Posted 15 May 2013 - 06:28 AM
Example file: (afile)
 
Hello,
How are you today?

some other lines...

That would be stored as

masterdb = {}
masterdb.afile = {}
masterdb.afile.filename = "afile"
masterdb.afile.dir = "/"
masterdb.afile = {"Hello,", "How are you today?", "", "some other lines..."}
KaoS #6
Posted 15 May 2013 - 11:47 AM
good stuff. Quick question, if there is a fake file and a real file on the computer which gets preference?
darkrising #7
Posted 15 May 2013 - 04:03 PM
good stuff. Quick question, if there is a fake file and a real file on the computer which gets preference?

The real file would probably take precedence over the fake one. :)/>
Lyqyd #8
Posted 15 May 2013 - 05:07 PM
The best option for this use case would be to override the fs calls to communicate with the server. It's a bit complex, but it means that user files are almost never stored on the local machine and are always synced to the server.
KaoS #9
Posted 15 May 2013 - 06:13 PM
here is a basic example. it only has code for reading files (not appending or writing) I'm sure you can figure that out

if not let me know, it's late now so I'm giving it a rest

CLIENT

rednet.open("left")
local nServerID=0
local function requestData(sRequest,...)
  if type(sRequest)~="string" then error("Incorrect input. String expected, got "..type(sRequest),2) end
  local ref,tEvt,tMsg=math.random(1,10000)
  rednet.send(nServerID,textutils.serialize({ref,sRequest,...}))
  repeat
   tEvt={os.pullEvent()}
   tMsg=type(tEvt[3])=="string" and textutils.unserialize(tEvt[3])
  until tEvt[1]=="rednet_message" and tEvt[2]==nServerID and type(tMsg)=="table" and tMsg[1]==ref and tMsg[2]==sRequest
  return unpack(tMsg,3)
end
local oldFS=fs
fs=setmetatable({},{__index=oldFS})
fs.list=function(sDir,...)
  local ls=oldFS.list(sDir,...)
  for k,v in pairs(requestData("dirList",sDir)) do
   table.insert(ls,v)
  end
  table.sort(ls)
  return ls
end
fs.open=function(sPath,sOperator,...)
  if not oldFS.exists(sPath) and sOperator=="r" then
   local tFile=requestData("getFile",sPath)
   if type(tFile)=="table" then
	return {readAll=function() if tFile.open then return table.concat(tFile.contents,"\n") end end,readLine=coroutine.wrap(function() for nLine=1,#tFile.contents do coroutine.yield(tFile.open and tFile.contents[nLine] or nil) end end),close=function() tFile.open=false end}
   end
  end
  return oldFS.open(sPath,sOperator,...)
end
fs.exists=function(sDir,...)
  return oldFS.exists(sDir,...) or requestData("doesExist",sDir)
end
fs.isDir=function(sDir,...)
  return oldFS.isDir(sDir,...)~=nil and oldFS.isDir(sDir,...) or requestData("isDir",sDir)
end
fs.isReadOnly=function(sDir,...)
  return oldFS.isReadOnly(sDir,...)~=nil and oldFS.isReadOnly(sDir,...) or requestData("isReadOnly",sDir)
end

FILESERVER

rednet.open("left")
while true do
  local tEvts={os.pullEvent()}
  if tEvts[1]=="rednet_message" and type(tEvts[3])=="string" then
   local tMsg=textutils.unserialize(tEvts[3])
   if type(tMsg)=="table" and type(tMsg[1])=="number" and tMsg[1]<=10000 and tMsg[1]>=1 and type(tMsg[2])=="string" then
	if tMsg[2]=="dirList" and type(tMsg[3])=="string" then
	 rednet.send(textutils.serialize({tMsg[1],tMsg[2],fs.list(tMsg[3])}))
	elseif tMsg[2]=="getFile" and type(tMsg[3])=="string" then
	 if fs.exists(tMsg[3]) and not fs.isDir(tMsg[3]) then
	  local oFile=fs.open(tMsg[3],"r")
	  local tFile={open=true,contents={}}
	  for sLine in oFile.read do
	   table.insert(tFile.contents,sLine)
	  end
	 end
	 rednet.send(textutils.serialize({tMsg[1],tMsg[2],tFile}))
	elseif tMsg[2]=="doesExist" and type(tMsg[3])=="string" then
	 rednet.send(textutils.serialize({tMsg[1],tMsg[2],fs.exists(tMsg[3])}))
	elseif tMsg[2]=="isDir" and type(tMsg[3])=="string" then
	 rednet.send(textutils.serialize({tMsg[1],tMsg[2],fs.isDir(tMsg[3])}))
	elseif tMsg[2]=="isReadOnly" and type(tMsg[3])=="string" then
	 rednet.send(textutils.serialize({tMsg[1],tMsg[2],fs.isReadOnly(tMsg[3])}))
	end
   end
  end
end
darkrising #10
Posted 16 May 2013 - 03:40 PM
-snip-

Thanks for taking the time to write this, I'll give it a try! :)/>
KaoS #11
Posted 16 May 2013 - 10:41 PM
derp… I sent you the untested version and deleted the tested version :(/> sorry, it was definitely late at night back then…

there will be a few bugs as this was the first writeup, just taking a look at the fileserver code in getFile it should be readLine not read
darkrising #12
Posted 17 May 2013 - 03:49 PM
derp… I sent you the untested version and deleted the tested version :(/> sorry, it was definitely late at night back then…

there will be a few bugs as this was the first writeup, just taking a look at the fileserver code in getFile it should be readLine not read

Still helped a lot, now I've seen how you've done it :)/>
KaoS #13
Posted 17 May 2013 - 05:37 PM
Still helped a lot, now I've seen how you've done it :)/>

Well it was my pleasure then :)/> I auto-follow every topic I participate in so if it doesn't work out let me know here, I've wanted to make something like this ever since making hidden files but it was just too much trouble to satisfy curiosity alone, I don't really have a use for it. Curiosity &amp; assisting someone who can use it is enough motivation
tesla1889 #14
Posted 18 May 2013 - 02:23 AM
for the server, the files could be stored in a specific folder that acts like the root directory of the virtual filesystem
KaoS #15
Posted 18 May 2013 - 07:52 AM
Indeed, it should be easily implementable though, as I was not privy to the login system I cannot include a root folder changing system based on logins, I trust darkrising is capable of it though