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:
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}"