///|
pub(all) struct Attributes {
kind : UInt
mode : UInt
links : UInt
uid : UInt
gid : UInt
size : UInt64
used : UInt64
fsid : UInt64
fileid : UInt64
modified_seconds : UInt
}
///|
fn read_attributes(r : @xdr.Reader) -> Attributes raise {
read_metadata(r).attributes
}
///|
fn read_metadata(r : @xdr.Reader) -> Metadata raise {
let kind = r.read_uint()
if kind < 1U || kind > 7U {
raise ProtocolError("invalid file type")
}
let mode = r.read_uint()
let links = r.read_uint()
let uid = r.read_uint()
let gid = r.read_uint()
let size = r.read_uhyper()
let used = r.read_uhyper()
let device_major = r.read_uint()
let device_minor = r.read_uint()
let fsid = r.read_uhyper()
let fileid = r.read_uhyper()
let accessed = read_timestamp(r)
let modified = read_timestamp(r)
let changed = read_timestamp(r)
{
attributes: {
kind,
mode,
links,
uid,
gid,
size,
used,
fsid,
fileid,
modified_seconds: modified.seconds,
},
device_major,
device_minor,
accessed,
modified,
changed,
}
}
///|
fn read_time(r : @xdr.Reader) -> UInt raise {
let seconds = r.read_uint()
if r.read_uint() >= 1000000000U {
raise ProtocolError("invalid nanoseconds")
}
seconds
}
///|
fn post_attributes(r : @xdr.Reader) -> Attributes? raise {
if r.read_bool() {
Some(read_attributes(r))
} else {
None
}
}
///|
fn read_wcc(r : @xdr.Reader) -> Unit raise {
if r.read_bool() {
ignore(r.read_uhyper())
ignore(read_time(r))
ignore(read_time(r))
}
ignore(post_attributes(r))
}
///|
fn require_success(r : @xdr.Reader) -> Unit raise {
let code = r.read_uint()
if code != 0U {
raise Status(code)
}
}
///|
/// Owned opaque file handle. Instances are validated before each wire use.
pub(all) struct Handle {
bytes : Bytes
}
///|
fn put_handle(w : @xdr.Writer, h : Handle) -> Unit raise {
if h.bytes.length() == 0 || h.bytes.length() > 64 {
raise InvalidArgument("file handle length")
}
w.write_opaque(h.bytes.to_array(), bound=64U)
}
///|
fn get_handle(r : @xdr.Reader) -> Handle raise {
let bytes = Bytes::from_array(r.read_opaque(bound=64U))
if bytes.length() == 0 {
raise ProtocolError("empty file handle")
}
{ bytes, }
}
///|
fn put_name(w : @xdr.Writer, name : String) -> Unit raise {
put_raw_name(w, @utf8.encode(name))
}
///|
fn limits(options : Options) -> @xdr.Limits {
{
max_bytes: options.max_record,
max_items: 1048576,
max_depth: 64,
max_schema_tokens: 65536,
}
}
///|
test "opaque handles use RFC length and padding" {
let w = @xdr.Writer::new()
put_handle(w, { bytes: b"abc", })
assert_eq(Bytes::from_array(w.bytes()), b"\x00\x00\x00\x03abc\x00")
let r = @xdr.Reader::new(w.bytes())
assert_eq(get_handle(r).bytes, b"abc")
r.finish()
try {
put_name(w, "../bad")
fail("accepted slash")
} catch {
InvalidArgument(_) => ()
other => raise other
}
}