r9p

git clone git://oldgit.suckless.org/r9p/
Log | Files | Refs

commit c72c151943eb8bb4a2b19f402fa127376981d8a0
parent 5fdc53adedcdf8da085f6c9c683f77a198bf2911
Author: Kris Maglione <jg@suckless.org>
Date:   Tue, 20 Mar 2007 00:22:59 -0400

Added Create, Remove, and Stat calls.

Diffstat:
r9p/client.rb | 113++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
r9p/fcall.rb | 3++-
r9p/test.rb | 18++++++++++++++++++
3 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/r9p/client.rb b/r9p/client.rb @@ -6,6 +6,8 @@ module R9P end class ProtocolException <Exception end + class RPCError <Exception + end class Client RootFid = 0 module Constants @@ -34,14 +36,14 @@ module R9P resp = dorpc Fcall::Tversion, :version => P9Version, :msize => 65535 if resp.version != P9Version - throw ProtocolException.new("Can't speak 9P version '#{resp.version}'") + raise ProtocolException, "Can't speak 9P version '#{resp.version}'" end @msize = resp.msize dorpc Fcall::Tattach, :fid => RootFid, :afid => NoFid, :uname => ENV['USER'], :aname => '' if root - path = root.split('/').reject{|v| v=='' } + path = splitpath(root) resp = dorpc Fcall::Twalk, :fid => RootFid, :newfid => RootFid, :wname => path end @@ -70,14 +72,19 @@ module R9P fcall = clas.new *args resp = @mux.rpc fcall if resp.kind_of? Fcall::Rerror - throw Exception.new("RPC returned error: #{fcall.class.inspect} #{fcall.fields.inspect}: #{resp.ename}") + raise RPCError, "RPC returned error (#{fcall.class.inspect}: #{fcall.fields.inspect}): #{resp.ename}" end if fcall.type != resp.type ^ 1 - throw ProtocolException.new("Missmatched RPC message types: #{fcall.class.inspect} => #{resp.class.inspect}") + raise ProtocolException, "Missmatched RPC message types: #{fcall.class.inspect} => #{resp.class.inspect}" end resp end + def splitpath(path) + path.split('/').reject{|v| v=='' } + end + private:splitpath + def getfid qsync { @fids.pop || @lastfid += 1 @@ -85,25 +92,40 @@ module R9P end def putfid(fid) qsync { - if @files.delete(fid) - @fids.push fid - else - throw Exception.new("Attempt to free unused fid") - end + @files.delete(fid) + @fids.push fid } end + private :getfid, :putfid - def open(path, mode = OREAD) - path = path.split('/').reject{|v| v=='' } + def walk(path) fid = getfid + dorpc Fcall::Twalk, :fid => RootFid, :newfid => fid, :wname => path + begin + yield fid + rescue + dorpc Fcall::Tclunk, :fid => fid + putfid fid + raise + end + end + + def _open(path, mode, block) + resp = fid = file = nil + + walk(path) do |fid| + fid = fid + resp = yield(fid) + end - resp = dorpc Fcall::Twalk, :fid => RootFid, :newfid => fid, :wname => path - file = File.new self, fid, mode + file = File.new(self, resp, fid, mode) do + putfid fid + end @files[fid] = file - if block_given? + if block begin - yield file + block.call file ensure file.close end @@ -111,22 +133,65 @@ module R9P file end end + private :_open, :walk + + def open(path, mode = OREAD, &block) + path = splitpath(path) + + _open(path, mode, block) do |fid| + dorpc Fcall::Topen, :fid => fid, :mode => mode + end + end + + def create(path, mode = OREAD, perm = 0, &block) + path = splitpath(path) + name = path.pop + + _open(path, mode, block) do |fid| + dorpc Fcall::Tcreate, :fid => fid, :mode => mode, :name => name, :perm => perm + end + end + + def remove(path) + path = splitpath(path) + + walk(path) do |fid| + dorpc Fcall::Tremove, :fid => fid + end + true + end + + def stat(path) + path = splitpath(path) + + walk(path) do |fid| + begin + resp = dorpc Fcall::Tstat, :fid => fid + resp.stat + ensure + dorpc Fcall::Tclunk, :fid => fid + end + end + rescue RPCError + return nil + end class File include Stat::Constants include Client::Constants include Qlock - def initialize(client, fid, mode) + attr_reader :fid, :qid, :mode, :offset, :iounit + def initialize(client, fcall, fid, mode, &cleanup) qlinit - @fid = fid @client = client - @offset = 0 + @fid = fid + @cleanup = cleanup @mode = mode - @fd = nil - - fcall = dorpc Fcall::Topen, :mode => mode @iounit = fcall.iounit @qid = fcall.qid + + @offset = 0 + @fd = nil end def stat @@ -176,7 +241,7 @@ module R9P end def readdir unless @qid.type.to_i&Qid::QTDIR - raise Exception.new("Can only call readdir on a directory") + raise Exception, "Can only call readdir on a directory" end data = '' begin @@ -192,7 +257,7 @@ module R9P qsync { dorpc Fcall::Tclunk } - @client.putfid @fid + @cleanup.call self @tg = @fid = @client = @qid = nil end @@ -208,7 +273,7 @@ module R9P def to_fd if @fd - throw Exception.new("File descriptor already open for file") + raise Exception, "File descriptor already open for file" end fds = Socket::pair Socket::PF_UNIX, Socket::SOCK_STREAM, 0 diff --git a/r9p/fcall.rb b/r9p/fcall.rb @@ -131,8 +131,9 @@ module R9P field :offset, :qword field :data, :dword, :string end - class Rwrite <Rread + class Rwrite <Fcall type 119 + field :count, :dword end class Tclunk <Fcall diff --git a/r9p/test.rb b/r9p/test.rb @@ -1,3 +1,4 @@ +#$debug = 5 require 'r9p.rb' module R9P @@ -12,10 +13,27 @@ module R9P } } } + c.open('/keys') { |f| puts "\n/keys:" print f.read } + + name = "Foo" + path = ["/rbar/foo", "/rbar/bar"] + if c.stat(path[0]) + name = "Bar" + t = path.shift + path.push t + else + c.create(path[1]) {} + end + puts "Stat of #{path[1]}: #{c.stat path[1]}" + c.remove(path[1]) + f = c.create(path[0], OWRITE) { |f| + f.write "#000000 #FFFFFF #000000 #{name}" + } + c.open('/ctl', OREAD) { |f| f.to_fd { |fd| print "From /ctl: #{fd.readline}"