From mboxrd@z Thu Jan 1 00:00:00 1970 Mime-Version: 1.0 (Apple Message framework v753) In-Reply-To: References: <326364c20801140111v1bf9b574p80ea0305edf09c14@mail.gmail.com> Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed Message-Id: <268E33BD-890D-4E18-962E-D868224ACC90@mac.com> Content-Transfer-Encoding: 7bit From: Gary Wright Subject: Re: [9fans] Easiest way to make a filesystem Date: Mon, 14 Jan 2008 16:00:13 -0500 To: Fans of the OS Plan 9 from Bell Labs <9fans@cse.psu.edu> Topicbox-Message-UUID: 2e40bef6-ead3-11e9-9d60-3106f5b1d025 On Jan 14, 2008, at 3:10 PM, roger peppe wrote: > i agree that it's too hard to create servers for simple filesystems. > > i've been wondering on and off for years what a "low-bar-to-entry" > filesystem > creating library might look like, and my current thoughts go > something like: I've been playing around with my own implementation of 9P in Ruby in an effort to explore this problem space and to better understand 9P. I don't know how many people on this list are familiar with ruby but it is pretty readable so I'll throw out some examples of my code and see what you think. The example below does everything locally, but I've got facilities for connecting and serving via TCP and the 9P- wire protocol. I'd appreciate comments/feedback. class Example < Device class Root < Directory root :mode => 0555 child 'readonly', :mode => 0600 child 'text', :mode => 0600, :contents => 'some text to start with' child 'subdir/' :mode => 0700 do child 'subfile' :mode => 0555 end child 'bob' :mode => 0600, :uid => 'bob' child 'all' :mode => 0444 # Lets define a Pipe resource class Pipe < Resource # incoming write requests get forwarded to aux object def write(fid, offset, data) aux.write(data) end # incoming read requests get forwarded to aux object def read(fid, offset, count) aux.read(count) end end # Everytime the Device gets instantiated construct # a unix domain socketpair, attach the ends to two # new Pipe resources and then put the Pipe resources # in the device namespace. child 'pipe/' :mode => 0700 do data, data1 = *UNIXSocket.socketpair child 'data', Pipe, :mode => 0600, :aux => data child 'data1', Pipe, :mode => 0600, :aux => data1 end end end # Everytime Example is instantiated we'll get a hiearchy like: # /readonly # /text # /subdir # /subdir/subfile # /bob # /all # /pipe # /pipe/data data/data1 connected via Unix pipe # /pipe/data1 # Access the device via 9P API device = Example.new device.version # Tversion a = device.auth # Tauth r = device.attach(a) # Tattach data = r.walk('pipe', 'data').open(ORDWR) data.write('some text') data1 = r.walk('pipe', 'data1').open puts data1.read # read until EOF (0 byte read) # Now construct a Plan 9-like namespace for access ns = NS.attach(Device.new) # start with memory fs device mounted at '/' ns.mkdir '/d1' ns.mkdir '/d2' ns['/d1'].mount Example.new # instantiate Example and mount ns['/d2'].mount Example.new # again but on a different directory d = ns['/d1/pipe/data'].open(ORDWR) d.write('some txt') puts ns['/d1/pipe/data1'].open.read # read from the other end