Class: RStyx::Client::File
- Inherits:
-
Object
- Object
- RStyx::Client::File
- Includes:
- Enumerable
- Defined in:
- lib/rstyx/client.rb
Overview
A Styx client’s view of a file. This class should probably never be directly instantiated, but only via Connection#open. The buffering algorithm in use here is somewhat based on the Buffering mix-in module in the Ruby OpenSSL module written by Goto Yuuzou, but modified a bit to provide for offset handling. Note that this class isn’t thread-safe.
Instance Attribute Summary collapse
-
#conn ⇒ Object
readonly
Returns the value of attribute conn.
-
#fid ⇒ Object
Returns the value of attribute fid.
-
#iounit ⇒ Object
Returns the value of attribute iounit.
-
#mode ⇒ Object
Returns the value of attribute mode.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#qid ⇒ Object
Returns the value of attribute qid.
-
#sync ⇒ Object
Returns the value of attribute sync.
Instance Method Summary collapse
- #<<(s) ⇒ Object
-
#close ⇒ Object
Close the file.
- #closed? ⇒ Boolean
-
#each(eol = $/) ⇒ Object
(also: #each_line)
Executes the block for evely line in the Styx file, where lines are separated by
eol
. - #eof? ⇒ Boolean (also: #eof)
- #flush ⇒ Object
- #getc ⇒ Object
-
#gets(eol = $/) ⇒ Object
Reads the next “line” from the Styx file; lines are separated by
eol
. -
#initialize(conn, path) ⇒ File
constructor
A new instance of File.
-
#open(mode, perm, create, &block) ⇒ Object
Open the file on the server.
- #print(*args) ⇒ Object
- #printf(s, *args) ⇒ Object
- #puts(*args) ⇒ Object
-
#read(size = -1)) ⇒ Object
Read at most
size
bytes from the Styx file or to the end of file if omitted. - #readchar ⇒ Object
-
#readline(eol = $/) ⇒ Object
Reads a line as with gets, but.
-
#readlines(eol = $/) ⇒ Object
Reads all of the lines in the Styx file, and returns them in an array.
- #rewind ⇒ Object
-
#seek(offset, whence) ⇒ Object
Seek in the file.
-
#stat ⇒ Object
Read the Stat information for the file.
-
#sysread(size = -1)) ⇒ Object
Reads
size
bytes from the Styx file and returns them as a string. -
#syswrite(data) ⇒ Object
Writes
data
to the Styx file. - #tell ⇒ Object
- #ungetc(c) ⇒ Object
- #write(s) ⇒ Object
Constructor Details
#initialize(conn, path) ⇒ File
Returns a new instance of File.
487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
# File 'lib/rstyx/client.rb', line 487 def initialize(conn, path) @conn = conn # the connection on which the file sits @path = path # pathname of the file @fid = -1 # the client's file identifier @qid = nil # the server's unique identifier for this file # maximum number of bytes that can be read or written to the file at a time @iounit = 0 @mode = -1 # mode under which the file is opened, -1 == not open @offset = 0 # File offset. This is the same as @boffset only after a seek @rboffset = 0 # Read buffer offset @eof = false @rbuffer = "" @sync = false # whether or not to buffer writes end |
Instance Attribute Details
#conn ⇒ Object (readonly)
Returns the value of attribute conn.
484 485 486 |
# File 'lib/rstyx/client.rb', line 484 def conn @conn end |
#fid ⇒ Object
Returns the value of attribute fid.
485 486 487 |
# File 'lib/rstyx/client.rb', line 485 def fid @fid end |
#iounit ⇒ Object
Returns the value of attribute iounit.
485 486 487 |
# File 'lib/rstyx/client.rb', line 485 def iounit @iounit end |
#mode ⇒ Object
Returns the value of attribute mode.
485 486 487 |
# File 'lib/rstyx/client.rb', line 485 def mode @mode end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
484 485 486 |
# File 'lib/rstyx/client.rb', line 484 def path @path end |
#qid ⇒ Object
Returns the value of attribute qid.
485 486 487 |
# File 'lib/rstyx/client.rb', line 485 def qid @qid end |
#sync ⇒ Object
Returns the value of attribute sync.
485 486 487 |
# File 'lib/rstyx/client.rb', line 485 def sync @sync end |
Instance Method Details
#<<(s) ⇒ Object
863 864 865 866 |
# File 'lib/rstyx/client.rb', line 863 def <<(s) do_write(s) return(self) end |
#close ⇒ Object
Close the file. This will flush all unwritten buffered data if any.
601 602 603 604 605 606 607 608 609 610 |
# File 'lib/rstyx/client.rb', line 601 def close flush rescue nil if @fid >= 0 # Clunk the fid @conn.tclunk(@fid) end @fid = -1 @iounit = 0 @mode = -1 end |
#closed? ⇒ Boolean
612 613 614 |
# File 'lib/rstyx/client.rb', line 612 def closed? return(@mode < 0) end |
#each(eol = $/) ⇒ Object Also known as: each_line
Executes the block for evely line in the Styx file, where lines are separated by eol
.
765 766 767 768 769 |
# File 'lib/rstyx/client.rb', line 765 def each(eol=$/) while line = self.gets(eol) yield line end end |
#eof? ⇒ Boolean Also known as: eof
807 808 809 810 811 812 |
# File 'lib/rstyx/client.rb', line 807 def eof? if !@eof && @rbuffer.empty? fill_rbuff end return(@eof && @rbuffer.empty?) end |
#flush ⇒ Object
895 896 897 898 899 900 |
# File 'lib/rstyx/client.rb', line 895 def flush osync = @sync @sync = true do_write "" @sync = osync end |
#getc ⇒ Object
792 793 794 795 |
# File 'lib/rstyx/client.rb', line 792 def getc c = read(1) return(c ? c[0] : nil) end |
#gets(eol = $/) ⇒ Object
Reads the next “line” from the Styx file; lines are separated by eol
. An eol
of nil reads the entire contents. Returns nil if called at end of file.
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 |
# File 'lib/rstyx/client.rb', line 743 def gets(eol=$/) idx = @rbuffer.index(eol) until @eof if idx break end fill_rbuff idx = @rbuffer.index(eol) end if eol.is_a?(Regexp) size = idx ? idx+$&.size : nil else size = idx ? idx+eol.size : nil end @offset += size return(consume_rbuff(size)) end |
#open(mode, perm, create, &block) ⇒ Object
Open the file on the server. If a block is passed to this method it will pass the file to the block and close the file automatically when the block terminates.
This follows more or less the same semantics as sys-open(2) on Inferno, performing an open with truncate, when a file is opened that doesn’t exist.
XXX - twalk should handle the case of MAXWELEM, as well as for
when the twalk message is too large to fit in the server's
designated msize.
mode
-
Integer representing the mode - see the constants in common.rb
perm
-
Permissions of the file (only used on open/create)
create
-
should we create the file if it doesn’t exist?
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'lib/rstyx/client.rb', line 519 def open(mode, perm, create, &block) dfid = @conn.get_free_fid basename = ::File.basename(@path) dirname = ::File.dirname(@path) # Walk to the dirname first twalk = Message::Twalk.new(:fid => @conn.rootfid, :newfid => dfid) twalk.path = dirname rwalk = @conn.(twalk) # if the rwalk has some other length than the number of path # elements in the original twalk, we have failed. if rwalk.qids.length != twalk.wnames.length raise StyxException.new(("#{path} no such file or directory")) end ropen = fid = nil begin # Next, walk to the basename from there, using a new fid fid = @conn.get_free_fid twalk = Message::Twalk.new(:fid => dfid, :newfid => fid) twalk.path = basename rwalk = @conn.(twalk) # Do a Topen if this succeeds open_msg = Message::Topen.new(:fid => fid, :mode => mode) ropen = @conn.(open_msg) @conn.tclunk(dfid) rescue Exception => e # If we are being directed to create the file if it doesn't # already exist, send a Tcreate message, and use the response # for it as the ropen (the two classes respond to exactly the # same messages--ah the wonders of duck typing!). If not, # or if that fails, this should propagate an exception upwards. if create # Alter the submitted permissions mask according to # the connection's umask perm &= ~(@conn.umask) create_msg = Message::Tcreate.new(:fid => dfid, :name => basename, :perm => perm, :mode => mode) ropen = @conn.(create_msg) fid = dfid else raise e end end # If we get here, we were able to successfully open or create # the file. @mode = mode @fid = fid @qid = ropen.qid @iounit = ropen.iounit # Determine if the file is actually a directory. Such a file # would have its Qid.qtype high bit set to 1. In this case, instead # of returning self, we return self wrapped in a Directory object. retval = self if twalk.wnames.length == 0 || (rwalk.qids[-1].qtype & 0x80 != 0) retval = Directory.new(self) end if block_given? begin yield retval ensure retval.close end else return(retval) end end |
#print(*args) ⇒ Object
883 884 885 886 887 888 |
# File 'lib/rstyx/client.rb', line 883 def print(*args) s = "" args.each{ |arg| s << arg.to_s } do_write(s) return(nil) end |
#printf(s, *args) ⇒ Object
890 891 892 893 |
# File 'lib/rstyx/client.rb', line 890 def printf(s, *args) do_write(s % args) return(nil) end |
#puts(*args) ⇒ Object
868 869 870 871 872 873 874 875 876 877 878 879 880 881 |
# File 'lib/rstyx/client.rb', line 868 def puts(*args) s = "" if args.empty? s << "\n" end args.each do |arg| s << arg.to_s if $/ && /\n\z/ !~ s s << "\n" end end do_write(s) return(nil) end |
#read(size = -1)) ⇒ Object
Read at most size
bytes from the Styx file or to the end of file if omitted. Returns nil if called at end of file.
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 |
# File 'lib/rstyx/client.rb', line 718 def read(size=-1) until @eof # Fill up the buffer until we have at least the requested # size, or until end of file if size is negative. if size > 0 && size <= @rbuffer.size break end fill_rbuff end # We managed to slurp the entire file! if size < 0 size = @rbuffer.size end @offset += size retval = consume_rbuff(size) || "" (size && retval.empty?) ? nil : retval end |
#readchar ⇒ Object
797 798 799 800 |
# File 'lib/rstyx/client.rb', line 797 def readchar raise EOFError if eof? getc end |
#readline(eol = $/) ⇒ Object
Reads a line as with gets, but
787 788 789 790 |
# File 'lib/rstyx/client.rb', line 787 def readline(eol=$/) raise EOFError if eof? return(gets(eol)) end |
#readlines(eol = $/) ⇒ Object
Reads all of the lines in the Styx file, and returns them in an array. Lines are separated by an optional separator eol
.
777 778 779 780 781 782 783 |
# File 'lib/rstyx/client.rb', line 777 def readlines(eol=$/) ary = [] while line = self.gets(eol) ary << line end ary end |
#rewind ⇒ Object
939 940 941 |
# File 'lib/rstyx/client.rb', line 939 def rewind seek(0, 0) end |
#seek(offset, whence) ⇒ Object
Seek in the file. The whence values may be one of SEEK_SET SEEK_CUR, or SEEK_END, as defined in rstyx/common, and they result in the offset being taken from the beginning of the file, relative to the current offset, or from the end of the file respectively.
XXX: A seek, no matter where it goes, will always invalidate
any buffering. This is fine for write buffers, but is
somewhat wasteful for the read buffers.
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 |
# File 'lib/rstyx/client.rb', line 913 def seek(offset, whence) # Before seeking, flush the write buffers flush s = self.stat case whence when 0 @offset = offset when 1 @offset += offset when 2 # We have to obtain the stat of the file to do this kind of seek. @offset = s.length + offset else raise StyxException.new("Invalid seek") end # After seeking, discard the read buffers @rbuffer = "" @rboffset = @offset @eof = (@offset >= s.length) return(@offset) end |
#stat ⇒ Object
Read the Stat information for the file.
returns: the RStyx::Message::Stat instance corresponding to
the file
592 593 594 595 |
# File 'lib/rstyx/client.rb', line 592 def stat rstat = @conn.(Message::Tstat.new(:fid => @fid)) return(rstat.stat) end |
#sysread(size = -1)) ⇒ Object
Reads size
bytes from the Styx file and returns them as a string. Do not mix with other methods that read from the Styx file or you may get unpredictable results.
948 949 950 951 952 953 954 |
# File 'lib/rstyx/client.rb', line 948 def sysread(size=-1) data, @offset = _sysread(size, @offset) if data.length == 0 return(nil) end return(data) end |
#syswrite(data) ⇒ Object
Writes data
to the Styx file. Returns the number of bytes written. do not mix with other methods that write to the Styx file or you may get unpredictable results.
960 961 962 963 |
# File 'lib/rstyx/client.rb', line 960 def syswrite(data) @offset, count = _syswrite(data, @offset) return(count) end |
#tell ⇒ Object
935 936 937 |
# File 'lib/rstyx/client.rb', line 935 def tell return(@offset) end |
#ungetc(c) ⇒ Object
802 803 804 805 |
# File 'lib/rstyx/client.rb', line 802 def ungetc(c) @rbuffer[0,0] = c.chr @offset -= 1 end |
#write(s) ⇒ Object
858 859 860 861 |
# File 'lib/rstyx/client.rb', line 858 def write(s) do_write(s) return(s.length) end |