# # Parser for XML-RPC call and response # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "date" require "xmlrpc/base64" require "xmlrpc/datetime" # add some methods to NQXML::Node module NQXML class Node def removeChild(node) @children.delete(node) end def childNodes @children end def hasChildNodes not @children.empty? end def [] (index) @children[index] end def nodeType if @entity.instance_of? NQXML::Text then :TEXT elsif @entity.instance_of? NQXML::Comment then :COMMENT #elsif @entity.instance_of? NQXML::Element then :ELEMENT elsif @entity.instance_of? NQXML::Tag then :ELEMENT else :ELSE end end def nodeValue #TODO: error when wrong Entity-type @entity.text end def nodeName #TODO: error when wrong Entity-type @entity.name end end # class Node end # module NQXML module XMLRPC class FaultException < StandardError attr_reader :faultCode, :faultString def initialize(faultCode, faultString) @faultCode = faultCode @faultString = faultString end # returns a hash def to_h {"faultCode" => @faultCode, "faultString" => @faultString} end end module Convert def self.int(str) str.to_i end def self.boolean(str) case str when "0" then false when "1" then true else raise "RPC-value of type boolean is wrong" end end def self.double(str) str.to_f end def self.dateTime(str) if str =~ /^(-?\d\d\d\d)(\d\d)(\d\d)T(\d\d):(\d\d):(\d\d)$/ then # TODO: Time.gm ??? .local ??? a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} XMLRPC::DateTime.new(*a) #if a[0] >= 1970 then # Time.gm(*a) #else # Date.new(*a[0,3]) #end else raise "wrong dateTime.iso8601 format" end end def self.base64(str) XMLRPC::Base64.decode(str) end def self.struct(hash) # convert to marhalled object klass = hash["___class___"] if klass.nil? or Config::ENABLE_MARSHALLING == false hash else begin mod = Module klass.split("::").each {|const| mod = mod.const_get(const.strip)} Thread.critical = true # let initialize take 0 parameters mod.module_eval %{ begin alias __initialize initialize rescue NameError end def initialize; end } obj = mod.new # restore old initialize mod.module_eval %{ undef initialize begin alias initialize __initialize rescue NameError end } Thread.critical = false hash.delete "___class___" hash.each {|k,v| obj.__set_instance_variable(k, v) } obj rescue hash end end end def self.fault(hash) if hash.kind_of? Hash and hash.size == 2 and hash.has_key? "faultCode" and hash.has_key? "faultString" and hash["faultCode"].kind_of? Integer and hash["faultString"].kind_of? String XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"]) else raise "wrong fault-structure: #{hash.inspect}" end end end # module Convert module XMLParser class AbstractTreeParser def parseMethodResponse(str) methodResponse_document(createCleanedTree(str)) end def parseMethodCall(str) methodCall_document(createCleanedTree(str)) end private # # remove all whitespaces but in the tags i4, int, boolean.... # and all comments # def removeWhitespacesAndComments(node) remove = [] childs = node.childNodes.to_a childs.each do |nd| case _nodeType(nd) when :TEXT # TODO: add nil? unless %w(i4 int boolean string double dateTime.iso8601 base64).include? node.nodeName if node.nodeName == "value" if not node.childNodes.to_a.detect {|n| _nodeType(n) == :ELEMENT}.nil? remove << nd if nd.nodeValue.strip == "" end else remove << nd if nd.nodeValue.strip == "" end end when :COMMENT remove << nd else removeWhitespacesAndComments(nd) end end remove.each { |i| node.removeChild(i) } end def nodeMustBe(node, name) cmp = case name when Array name.include?(node.nodeName) when String name == node.nodeName else raise "error" end if not cmp then raise "wrong xml-rpc (name)" end node end # # returns, when successfully the only child-node # def hasOnlyOneChild(node, name=nil) if node.childNodes.to_a.size != 1 raise "wrong xml-rpc (size)" end if name != nil then nodeMustBe(node.firstChild, name) end end def assert(b) if not b then raise "assert-fail" end end # the node `node` has empty string or string def text_zero_one(node) nodes = node.childNodes.to_a.size if nodes == 1 text(node.firstChild) elsif nodes == 0 "" else raise "wrong xml-rpc (size)" end end def integer(node) #TODO: check string for float because to_i returnsa # 0 when wrong string nodeMustBe(node, %w(i4 int)) hasOnlyOneChild(node) Convert.int(text(node.firstChild)) end def boolean(node) nodeMustBe(node, "boolean") hasOnlyOneChild(node) Convert.boolean(text(node.firstChild)) end def v_nil(node) nodeMustBe(node, "nil") assert( node.childNodes.to_a.size == 0 ) nil end def string(node) nodeMustBe(node, "string") text_zero_one(node) end def double(node) #TODO: check string for float because to_f returnsa # 0.0 when wrong string nodeMustBe(node, "double") hasOnlyOneChild(node) Convert.double(text(node.firstChild)) end def dateTime(node) nodeMustBe(node, "dateTime.iso8601") hasOnlyOneChild(node) Convert.dateTime( text(node.firstChild) ) end def base64(node) nodeMustBe(node, "base64") #hasOnlyOneChild(node) Convert.base64(text_zero_one(node)) end def member(node) nodeMustBe(node, "member") assert( node.childNodes.to_a.size == 2 ) [ name(node[0]), value(node[1]) ] end def name(node) nodeMustBe(node, "name") #hasOnlyOneChild(node) text_zero_one(node) end def array(node) nodeMustBe(node, "array") hasOnlyOneChild(node, "data") data(node.firstChild) end def data(node) nodeMustBe(node, "data") node.childNodes.to_a.collect do |val| value(val) end end def param(node) nodeMustBe(node, "param") hasOnlyOneChild(node, "value") value(node.firstChild) end def methodResponse(node) nodeMustBe(node, "methodResponse") hasOnlyOneChild(node, %w(params fault)) child = node.firstChild case child.nodeName when "params" [ true, params(child,false) ] when "fault" [ false, fault(child) ] else raise "unexpected error" end end def methodName(node) nodeMustBe(node, "methodName") hasOnlyOneChild(node) text(node.firstChild) end def params(node, call=true) nodeMustBe(node, "params") if call node.childNodes.to_a.collect do |n| param(n) end else # response (only one param) hasOnlyOneChild(node) param(node.firstChild) end end def fault(node) nodeMustBe(node, "fault") hasOnlyOneChild(node, "value") f = value(node.firstChild) Convert.fault(f) end # _nodeType is defined in the subclass def text(node) assert( _nodeType(node) == :TEXT ) assert( node.hasChildNodes == false ) assert( node.nodeValue != nil ) node.nodeValue.to_s end def struct(node) nodeMustBe(node, "struct") hash = {} node.childNodes.to_a.each do |me| n, v = member(me) hash[n] = v end Convert.struct(hash) end def value(node) nodeMustBe(node, "value") nodes = node.childNodes.to_a.size if nodes == 0 return "" elsif nodes > 1 raise "wrong xml-rpc (size)" end child = node.firstChild case _nodeType(child) when :TEXT text_zero_one(node) when :ELEMENT case child.nodeName when "i4", "int" then integer(child) when "boolean" then boolean(child) when "string" then string(child) when "double" then double(child) when "dateTime.iso8601" then dateTime(child) when "base64" then base64(child) when "struct" then struct(child) when "array" then array(child) when "nil" if Config::ENABLE_NIL_PARSER v_nil(child) else raise "wrong/unknown XML-RPC type 'nil'" end else raise "wrong/unknown XML-RPC type" end else raise "wrong type of node" end end def methodCall(node) nodeMustBe(node, "methodCall") assert( (1..2).include?( node.childNodes.to_a.size ) ) name = methodName(node[0]) if node.childNodes.to_a.size == 2 then pa = params(node[1]) else # no parameters given pa = [] end [name, pa] end end # module TreeParserMixin class AbstractStreamParser def parseMethodResponse(str) parser = @parser_class.new parser.parse(str) raise "No valid method response!" if parser.method_name != nil if parser.fault != nil # is a fault structure [false, parser.fault] else # is a normal return value raise "Missing return value!" if parser.params.size == 0 raise "Too many return values. Only one allowed!" if parser.params.size > 1 [true, parser.params[0]] end end def parseMethodCall(str) parser = @parser_class.new parser.parse(str) raise "No valid method call - missing method name!" if parser.method_name.nil? [parser.method_name, parser.params] end end module StreamParserMixin attr_reader :params attr_reader :method_name attr_reader :fault def initialize(*a) super(*a) @params = [] @values = [] @val_stack = [] @names = [] @name = [] @structs = [] @struct = {} @method_name = nil @fault = nil @data = nil end def startElement(name, attrs=[]) @data = nil case name when "value" @value = nil when "nil" raise "wrong/unknown XML-RPC type 'nil'" unless Config::ENABLE_NIL_PARSER @value = :nil when "array" @val_stack << @values @values = [] when "struct" @names << @name @name = [] @structs << @struct @struct = {} end end def endElement(name) @data ||= "" case name when "string" @value = @data when "i4", "int" @value = Convert.int(@data) when "boolean" @value = Convert.boolean(@data) when "double" @value = Convert.double(@data) when "dateTime.iso8601" @value = Convert.dateTime(@data) when "base64" @value = Convert.base64(@data) when "value" @value = @data if @value.nil? @values << (@value == :nil ? nil : @value) when "array" @value = @values @values = @val_stack.pop when "struct" @value = Convert.struct(@struct) @name = @names.pop @struct = @structs.pop when "name" @name[0] = @data when "member" @struct[@name[0]] = @values.pop when "param" @params << @values[0] @values = [] when "fault" @fault = Convert.fault(@values[0]) when "methodName" @method_name = @data end @data = nil end def character(data) if @data @data << data else @data = data end end end # module StreamParserMixin # --------------------------------------------------------------------------- class XMLStreamParser < AbstractStreamParser def initialize require "xmlparser" eval %{ class XMLRPCParser < ::XMLParser include StreamParserMixin end } @parser_class = XMLRPCParser end end # class XMLStreamParser # --------------------------------------------------------------------------- class NQXMLStreamParser < AbstractStreamParser def initialize require "nqxml/streamingparser" @parser_class = XMLRPCParser end class XMLRPCParser include StreamParserMixin def parse(str) parser = NQXML::StreamingParser.new(str) parser.each do |ele| case ele when NQXML::Text @data = ele.text #character(ele.text) when NQXML::Tag if ele.isTagEnd endElement(ele.name) else startElement(ele.name, ele.attrs) end end end # do end # method parse end # class XMLRPCParser end # class NQXMLStreamParser # --------------------------------------------------------------------------- class XMLTreeParser < AbstractTreeParser def initialize require "xmltreebuilder" # The new XMLParser library (0.6.2+) uses a slightly different DOM implementation. # The following code removes the differences between both versions. if defined? XML::DOM::Builder return if defined? XML::DOM::Node::DOCUMENT # code below has been already executed klass = XML::DOM::Node klass.const_set("DOCUMENT", klass::DOCUMENT_NODE) klass.const_set("TEXT", klass::TEXT_NODE) klass.const_set("COMMENT", klass::COMMENT_NODE) klass.const_set("ELEMENT", klass::ELEMENT_NODE) end end private def _nodeType(node) tp = node.nodeType if tp == XML::SimpleTree::Node::TEXT then :TEXT elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT else :ELSE end end def methodResponse_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodResponse") methodResponse(node.firstChild) end def methodCall_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodCall") methodCall(node.firstChild) end def createCleanedTree(str) doc = XML::SimpleTreeBuilder.new.parse(str) doc.documentElement.normalize removeWhitespacesAndComments(doc) doc end end # class XMLParser # --------------------------------------------------------------------------- class NQXMLTreeParser < AbstractTreeParser def initialize require "nqxml/treeparser" end private def _nodeType(node) node.nodeType end def methodResponse_document(node) methodResponse(node) end def methodCall_document(node) methodCall(node) end def createCleanedTree(str) doc = ::NQXML::TreeParser.new(str).document.rootNode removeWhitespacesAndComments(doc) doc end end # class NQXMLTreeParser # --------------------------------------------------------------------------- class REXMLStreamParser < AbstractStreamParser def initialize require "rexml/document" @parser_class = StreamListener end class StreamListener include StreamParserMixin alias :tag_start :startElement alias :tag_end :endElement alias :text :character alias :cdata :character def method_missing(*a) # ignore end def parse(str) parser = REXML::Document.parse_stream(str, self) end end end # --------------------------------------------------------------------------- class XMLScanStreamParser < AbstractStreamParser def initialize require "xmlscan/parser" @parser_class = XMLScanParser end class XMLScanParser include StreamParserMixin Entities = { "lt" => "<", "gt" => ">", "amp" => "&", "quot" => '"', "apos" => "'" } def parse(str) parser = XMLScan::XMLParser.new(self) parser.parse(str) end alias :on_stag :startElement alias :on_etag :endElement def on_stag_end(name); end def on_stag_end_empty(name) startElement(name) endElement(name) end def on_chardata(str) character(str) end def on_cdata(str) character(str) end def on_entityref(ent) str = Entities[ent] if str character(str) else raise "unknown entity" end end def on_charref(code) character(code.chr) end def on_charref_hex(code) character(code.chr) end def method_missing(*a) end # TODO: call/implement? # valid_name? # valid_chardata? # valid_char? # parse_error end end # --------------------------------------------------------------------------- XMLParser = XMLTreeParser NQXMLParser = NQXMLTreeParser Classes = [XMLStreamParser, XMLTreeParser, NQXMLStreamParser, NQXMLTreeParser, REXMLStreamParser, XMLScanStreamParser] end # module XMLParser end # module XMLRPC '#n416'>416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 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 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
/*
  Copyright (c) 2006-2009 Z RESEARCH, Inc. <http://www.zresearch.com>
  This file is part of GlusterFS.

  GlusterFS is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published
  by the Free Software Foundation; either version 3 of the License,
  or (at your option) any later version.

  GlusterFS is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see
  <http://www.gnu.org/licenses/>.
*/

#ifndef _PROTOCOL_H
#define _PROTOCOL_H

#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif

#include <inttypes.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <unistd.h>
#include <fcntl.h>

#include "byte-order.h"

/* Any changes in the protocol structure or adding new '[f,m]ops' needs to 
 * bump the protocol version by "0.1" 
 */

#define GF_PROTOCOL_VERSION "2.1"

struct gf_stat {
	uint64_t ino;
	uint64_t size;
	uint64_t blocks;
	uint32_t dev;
	uint32_t rdev;
	uint32_t mode;
	uint32_t nlink;
	uint32_t uid;
	uint32_t gid;
	uint32_t blksize;
	uint32_t atime;
	uint32_t atime_nsec;
	uint32_t mtime;
	uint32_t mtime_nsec;
	uint32_t ctime;
	uint32_t ctime_nsec;
} __attribute__((packed));


static inline void
gf_stat_to_stat (struct gf_stat *gf_stat, struct stat *stat)
{
	stat->st_dev          = ntoh32 (gf_stat->dev);
	stat->st_ino          = ntoh64 (gf_stat->ino);
	stat->st_mode         = ntoh32 (gf_stat->mode);
	stat->st_nlink        = ntoh32 (gf_stat->nlink);
	stat->st_uid          = ntoh32 (gf_stat->uid);
	stat->st_gid          = ntoh32 (gf_stat->gid);
	stat->st_rdev         = ntoh32 (gf_stat->rdev);
	stat->st_size         = ntoh64 (gf_stat->size);
	stat->st_blksize      = ntoh32 (gf_stat->blksize);
	stat->st_blocks       = ntoh64 (gf_stat->blocks);
	stat->st_atime        = ntoh32 (gf_stat->atime);
	stat->st_mtime        = ntoh32 (gf_stat->mtime);
	stat->st_ctime        = ntoh32 (gf_stat->ctime);
	/* TODO: handle nsec */
}


static inline void
gf_stat_from_stat (struct gf_stat *gf_stat, struct stat *stat)
{
	gf_stat->dev         = hton32 (stat->st_dev);
	gf_stat->ino         = hton64 (stat->st_ino);
	gf_stat->mode        = hton32 (stat->st_mode);
	gf_stat->nlink       = hton32 (stat->st_nlink);
	gf_stat->uid         = hton32 (stat->st_uid);
	gf_stat->gid         = hton32 (stat->st_gid);
	gf_stat->rdev        = hton32 (stat->st_rdev);
	gf_stat->size        = hton64 (stat->st_size);
	gf_stat->blksize     = hton32 (stat->st_blksize);
	gf_stat->blocks      = hton64 (stat->st_blocks);
	gf_stat->atime       = hton32 (stat->st_atime);
	gf_stat->mtime       = hton32 (stat->st_mtime);
	gf_stat->ctime       = hton32 (stat->st_ctime);
	/* TODO: handle nsec */
}


struct gf_statfs {
	uint64_t bsize;
	uint64_t frsize;
	uint64_t blocks;
	uint64_t bfree;
	uint64_t bavail;
	uint64_t files;
	uint64_t ffree;
	uint64_t favail;
	uint64_t fsid;
	uint64_t flag;
	uint64_t namemax;
} __attribute__((packed));


static inline void
gf_statfs_to_statfs (struct gf_statfs *gf_stat, struct statvfs *stat)
{
	stat->f_bsize   = ntoh64 (gf_stat->bsize);
	stat->f_frsize  = ntoh64 (gf_stat->frsize);
	stat->f_blocks  = ntoh64 (gf_stat->blocks);
	stat->f_bfree   = ntoh64 (gf_stat->bfree);
	stat->f_bavail  = ntoh64 (gf_stat->bavail);
	stat->f_files   = ntoh64 (gf_stat->files);
	stat->f_ffree   = ntoh64 (gf_stat->ffree);
	stat->f_favail  = ntoh64 (gf_stat->favail);
	stat->f_fsid    = ntoh64 (gf_stat->fsid);
	stat->f_flag    = ntoh64 (gf_stat->flag);
	stat->f_namemax = ntoh64 (gf_stat->namemax);
}


static inline void
gf_statfs_from_statfs (struct gf_statfs *gf_stat, struct statvfs *stat)
{
	gf_stat->bsize   = hton64 (stat->f_bsize);
	gf_stat->frsize  = hton64 (stat->f_frsize);
	gf_stat->blocks  = hton64 (stat->f_blocks);
	gf_stat->bfree   = hton64 (stat->f_bfree);
	gf_stat->bavail  = hton64 (stat->f_bavail);
	gf_stat->files   = hton64 (stat->f_files);
	gf_stat->ffree   = hton64 (stat->f_ffree);
	gf_stat->favail  = hton64 (stat->f_favail);
	gf_stat->fsid    = hton64 (stat->f_fsid);
	gf_stat->flag    = hton64 (stat->f_flag);
	gf_stat->namemax = hton64 (stat->f_namemax);
}


struct gf_flock {
	uint16_t type;
	uint16_t whence;
	uint64_t start;
	uint64_t len;
	uint32_t pid;
} __attribute__((packed));


static inline void
gf_flock_to_flock (struct gf_flock *gf_flock, struct flock *flock)
{
	flock->l_type   = ntoh16 (gf_flock->type);
	flock->l_whence = ntoh16 (gf_flock->whence);
	flock->l_start  = ntoh64 (gf_flock->start);
	flock->l_len    = ntoh64 (gf_flock->len);
	flock->l_pid    = ntoh32 (gf_flock->pid);
}


static inline void
gf_flock_from_flock (struct gf_flock *gf_flock, struct flock *flock)
{
	gf_flock->type   = hton16 (flock->l_type);
	gf_flock->whence = hton16 (flock->l_whence);
	gf_flock->start  = hton64 (flock->l_start);
	gf_flock->len    = hton64 (flock->l_len);
	gf_flock->pid    = hton32 (flock->l_pid);
}


struct gf_timespec {
	uint32_t tv_sec;
	uint32_t tv_nsec;
} __attribute__((packed));


static inline void
gf_timespec_to_timespec (struct gf_timespec *gf_ts, struct timespec *ts)
{

	ts[0].tv_sec  = ntoh32 (gf_ts[0].tv_sec);
	ts[0].tv_nsec = ntoh32 (gf_ts[0].tv_nsec);
	ts[1].tv_sec  = ntoh32 (gf_ts[1].tv_sec);
	ts[1].tv_nsec = ntoh32 (gf_ts[1].tv_nsec);
}


static inline void
gf_timespec_from_timespec (struct gf_timespec *gf_ts, struct timespec *ts)
{
	gf_ts[0].tv_sec  = hton32 (ts[0].tv_sec);
	gf_ts[0].tv_nsec = hton32 (ts[0].tv_nsec);
	gf_ts[1].tv_sec  = hton32 (ts[1].tv_sec);
	gf_ts[1].tv_nsec = hton32 (ts[1].tv_nsec);
}


#define GF_O_ACCMODE           003
#define GF_O_RDONLY             00
#define GF_O_WRONLY             01
#define GF_O_RDWR               02
#define GF_O_CREAT            0100
#define GF_O_EXCL             0200
#define GF_O_NOCTTY           0400
#define GF_O_TRUNC           01000
#define GF_O_APPEND          02000
#define GF_O_NONBLOCK        04000
#define GF_O_SYNC           010000
#define GF_O_ASYNC          020000

#define GF_O_DIRECT         040000
#define GF_O_DIRECTORY     0200000
#define GF_O_NOFOLLOW      0400000
#define GF_O_NOATIME      01000000
#define GF_O_CLOEXEC      02000000

#define GF_O_LARGEFILE     0100000

#define XLATE_BIT(from, to, bit)    do {                \
                if (from & bit)                         \
                        to = to | GF_##bit;             \
        } while (0)

#define UNXLATE_BIT(from, to, bit)  do {                \
                if (from & GF_##bit)                    \
                        to = to | bit;                  \
        } while (0)

#define XLATE_ACCESSMODE(from, to) do {                 \
                switch (from & O_ACCMODE) {             \
                case O_RDONLY: to |= GF_O_RDONLY;       \
                        break;                          \
                case O_WRONLY: to |= GF_O_WRONLY;       \
                        break;                          \
                case O_RDWR: to |= GF_O_RDWR;           \
                        break;                          \
                }                                       \
        } while (0)

#define UNXLATE_ACCESSMODE(from, to) do {               \
                switch (from & GF_O_ACCMODE) {          \
                case GF_O_RDONLY: to |= O_RDONLY;       \
                        break;                          \
                case GF_O_WRONLY: to |= O_WRONLY;       \
                        break;                          \
                case GF_O_RDWR: to |= O_RDWR;           \
                        break;                          \
                }                                       \
        } while (0)

static inline uint32_t
gf_flags_from_flags (uint32_t flags)
{
        uint32_t gf_flags = 0;

        XLATE_ACCESSMODE (flags, gf_flags);

        XLATE_BIT (flags, gf_flags, O_CREAT);
        XLATE_BIT (flags, gf_flags, O_EXCL);
        XLATE_BIT (flags, gf_flags, O_NOCTTY);
        XLATE_BIT (flags, gf_flags, O_TRUNC);
        XLATE_BIT (flags, gf_flags, O_APPEND);
        XLATE_BIT (flags, gf_flags, O_NONBLOCK);
        XLATE_BIT (flags, gf_flags, O_SYNC);
        XLATE_BIT (flags, gf_flags, O_ASYNC);

        XLATE_BIT (flags, gf_flags, O_DIRECT);
        XLATE_BIT (flags, gf_flags, O_DIRECTORY);
        XLATE_BIT (flags, gf_flags, O_NOFOLLOW);
#ifdef O_NOATIME
        XLATE_BIT (flags, gf_flags, O_NOATIME);
#endif
#ifdef O_CLOEXEC
        XLATE_BIT (flags, gf_flags, O_CLOEXEC);
#endif
        XLATE_BIT (flags, gf_flags, O_LARGEFILE);

        return gf_flags;
}

static inline uint32_t
gf_flags_to_flags (uint32_t gf_flags)
{
        uint32_t flags = 0;

        UNXLATE_ACCESSMODE (gf_flags, flags);

        UNXLATE_BIT (gf_flags, flags, O_CREAT);
        UNXLATE_BIT (gf_flags, flags, O_EXCL);
        UNXLATE_BIT (gf_flags, flags, O_NOCTTY);
        UNXLATE_BIT (gf_flags, flags, O_TRUNC);
        UNXLATE_BIT (gf_flags, flags, O_APPEND);
        UNXLATE_BIT (gf_flags, flags, O_NONBLOCK);
        UNXLATE_BIT (gf_flags, flags, O_SYNC);
        UNXLATE_BIT (gf_flags, flags, O_ASYNC);

        UNXLATE_BIT (gf_flags, flags, O_DIRECT);
        UNXLATE_BIT (gf_flags, flags, O_DIRECTORY);
        UNXLATE_BIT (gf_flags, flags, O_NOFOLLOW);
#ifdef O_NOATIME
        UNXLATE_BIT (gf_flags, flags, O_NOATIME);
#endif
#ifdef O_CLOEXEC
        UNXLATE_BIT (gf_flags, flags, O_CLOEXEC);
#endif
        UNXLATE_BIT (gf_flags, flags, O_LARGEFILE);

        return flags;
}


typedef struct {
	uint64_t ino;
	char     path[0];     /* NULL terminated */
} __attribute__((packed)) gf_fop_stat_req_t;;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_stat_rsp_t;


typedef struct {
	uint64_t ino;
	uint32_t size;
	char     path[0];     /* NULL terminated */
} __attribute__((packed)) gf_fop_readlink_req_t;
typedef struct {
	char     path[0]; /* NULL terminated */
} __attribute__((packed)) gf_fop_readlink_rsp_t;


typedef struct {
	uint64_t par;
	uint64_t dev;
	uint32_t mode;
	char     path[0];     /* NULL terminated */
	char     bname[0]; /* NULL terminated */
} __attribute__((packed)) gf_fop_mknod_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_mknod_rsp_t;


typedef struct {
	uint64_t par;
	uint32_t mode;
	char     path[0];     /* NULL terminated */
	char     bname[0]; /* NULL terminated */
} __attribute__((packed)) gf_fop_mkdir_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_mkdir_rsp_t;


typedef struct {
	uint64_t par;
	char     path[0];     /* NULL terminated */
	char     bname[0]; /* NULL terminated */
} __attribute__((packed)) gf_fop_unlink_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_unlink_rsp_t;


typedef struct {
	uint64_t par;
	char     path[0];
	char     bname[0]; /* NULL terminated */
} __attribute__((packed)) gf_fop_rmdir_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_rmdir_rsp_t;


typedef struct {
	uint64_t par;
	char     path[0];
	char     bname[0];
	char     linkname[0];
} __attribute__((packed)) gf_fop_symlink_req_t;
typedef struct {
	struct gf_stat stat;
}__attribute__((packed)) gf_fop_symlink_rsp_t;


typedef struct {
	uint64_t   oldpar;
	uint64_t   newpar;
	char       oldpath[0];
	char       oldbname[0]; /* NULL terminated */
	char       newpath[0];
	char       newbname[0]; /* NULL terminated */
} __attribute__((packed)) gf_fop_rename_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_rename_rsp_t;


typedef struct {
	uint64_t   oldino;
	uint64_t   newpar;
	char       oldpath[0];
	char       newpath[0];
	char       newbname[0];
}__attribute__((packed)) gf_fop_link_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_link_rsp_t;


typedef struct {
	uint64_t  ino;
	uint32_t  mode;
	char      path[0];
} __attribute__((packed)) gf_fop_chmod_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_chmod_rsp_t;


typedef struct {
	uint64_t ino;
	uint32_t uid;
	uint32_t gid;
	char     path[0];
} __attribute__((packed)) gf_fop_chown_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_chown_rsp_t;


typedef struct {
	uint64_t ino;
	uint64_t offset;
	char     path[0];
} __attribute__((packed)) gf_fop_truncate_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_truncate_rsp_t;


typedef struct {
	uint64_t ino;
	uint32_t flags;
	char     path[0];
} __attribute__((packed)) gf_fop_open_req_t;
typedef struct {
	int64_t fd;
} __attribute__((packed)) gf_fop_open_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint64_t offset;
	uint32_t size;
} __attribute__((packed)) gf_fop_read_req_t;
typedef struct {
	struct gf_stat stat;
	char buf[0];
} __attribute__((packed)) gf_fop_read_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint64_t offset;
	uint32_t size;
} __attribute__((packed)) gf_fop_write_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_write_rsp_t;


typedef struct {
	uint64_t ino;
	char     path[0];
} __attribute__((packed)) gf_fop_statfs_req_t;
typedef struct {
	struct gf_statfs statfs;
} __attribute__((packed)) gf_fop_statfs_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
} __attribute__((packed)) gf_fop_flush_req_t;
typedef struct { } __attribute__((packed)) gf_fop_flush_rsp_t;


typedef struct fsync_req {
	uint64_t ino;
	int64_t  fd;
	uint32_t data;
} __attribute__((packed)) gf_fop_fsync_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_fsync_rsp_t;


typedef struct {
	uint64_t ino;
	uint32_t flags;
	uint32_t dict_len;
	char     dict[0];
	char     path[0];
} __attribute__((packed)) gf_fop_setxattr_req_t;
typedef struct { } __attribute__((packed)) gf_fop_setxattr_rsp_t;


typedef struct {
        uint64_t ino;
	int64_t  fd;
	uint32_t flags;
	uint32_t dict_len;
	char     dict[0];
} __attribute__((packed)) gf_fop_fsetxattr_req_t;
typedef struct { } __attribute__((packed)) gf_fop_fsetxattr_rsp_t;


typedef struct {
	uint64_t ino;
	uint32_t flags;
	uint32_t dict_len;
	char     dict[0];
	char     path[0];
} __attribute__((packed)) gf_fop_xattrop_req_t;

typedef struct {
	uint32_t dict_len;
	char  dict[0];
} __attribute__((packed)) gf_fop_xattrop_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint32_t flags;
	uint32_t dict_len;
	char     dict[0];
} __attribute__((packed)) gf_fop_fxattrop_req_t;

typedef struct {
	uint32_t dict_len;
	char  dict[0];
} __attribute__((packed)) gf_fop_fxattrop_rsp_t;


typedef struct {
	uint64_t ino;
	uint32_t namelen;
	char     path[0];
	char     name[0];
} __attribute__((packed)) gf_fop_getxattr_req_t;
typedef struct {
	uint32_t dict_len;
	char     dict[0];
} __attribute__((packed)) gf_fop_getxattr_rsp_t;


typedef struct {
        uint64_t ino;
	int64_t  fd;
        uint32_t namelen;
	char     name[0];
} __attribute__((packed)) gf_fop_fgetxattr_req_t;
typedef struct {
	uint32_t dict_len;
	char     dict[0];
} __attribute__((packed)) gf_fop_fgetxattr_rsp_t;


typedef struct {
	uint64_t ino;
	char     path[0];
	char     name[0];
} __attribute__((packed)) gf_fop_removexattr_req_t;
typedef struct { } __attribute__((packed)) gf_fop_removexattr_rsp_t;


typedef struct {
	uint64_t ino;
	char     path[0];
} __attribute__((packed)) gf_fop_opendir_req_t;
typedef struct {
	int64_t fd;
} __attribute__((packed)) gf_fop_opendir_rsp_t;


typedef struct fsyncdir_req {
	uint64_t ino;
	int64_t  fd;
	int32_t  data;
} __attribute__((packed)) gf_fop_fsyncdir_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_fsyncdir_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint64_t offset;
	uint32_t size;
} __attribute__((packed)) gf_fop_readdir_req_t;
typedef struct {
	uint32_t size;
	char     buf[0];
} __attribute__((packed)) gf_fop_readdir_rsp_t;


typedef struct  {
	uint64_t ino;
	uint32_t mask;
	char     path[0];
} __attribute__((packed)) gf_fop_access_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_access_rsp_t;


typedef struct {
	uint64_t par;
	uint32_t flags;
	uint32_t mode;
	char     path[0];
	char     bname[0];
} __attribute__((packed)) gf_fop_create_req_t;
typedef struct {
	struct gf_stat stat;
	uint64_t       fd;
} __attribute__((packed)) gf_fop_create_rsp_t;



typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint64_t offset;
} __attribute__((packed)) gf_fop_ftruncate_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_ftruncate_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
} __attribute__((packed)) gf_fop_fstat_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_fstat_rsp_t;


typedef struct {
	uint64_t        ino;
	int64_t         fd;
	uint32_t        cmd;
	uint32_t        type;
	struct gf_flock flock;
} __attribute__((packed)) gf_fop_lk_req_t;
typedef struct {
	struct gf_flock flock;
} __attribute__((packed)) gf_fop_lk_rsp_t;

typedef struct {
	uint64_t ino;
	uint32_t cmd;
	uint32_t type;
	struct gf_flock flock;
	char     path[0];
        char     volume[0];
} __attribute__((packed)) gf_fop_inodelk_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_inodelk_rsp_t;

typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint32_t cmd;
	uint32_t type;
	struct gf_flock flock;
        char volume[0];
} __attribute__((packed)) gf_fop_finodelk_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_finodelk_rsp_t;

typedef struct {
	uint64_t  ino;
	uint32_t  cmd;
	uint32_t  type;
	uint64_t  namelen;
	char      path[0];
	char      name[0];
        char      volume[0];
} __attribute__((packed)) gf_fop_entrylk_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_entrylk_rsp_t;

typedef struct {
	uint64_t  ino;
	int64_t   fd;
	uint32_t  cmd;
	uint32_t  type;
	uint64_t  namelen;
	char      name[0];
        char      volume[0];
} __attribute__((packed)) gf_fop_fentrylk_req_t;
typedef struct {
} __attribute__((packed)) gf_fop_fentrylk_rsp_t;

typedef struct {
	uint64_t           ino;
	struct gf_timespec tv[2];
	char               path[0];
} __attribute__((packed)) gf_fop_utimens_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_utimens_rsp_t;

typedef struct {
	uint64_t  ino;
	uint64_t  fd;
	uint32_t  mode;
} __attribute__((packed)) gf_fop_fchmod_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_fchmod_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint32_t uid;
	uint32_t gid;
} __attribute__((packed)) gf_fop_fchown_req_t;
typedef struct {
	struct gf_stat stat;
} __attribute__((packed)) gf_fop_fchown_rsp_t;


typedef struct {
	uint64_t ino; /* NOTE: used only in case of 'root' lookup */
	uint64_t par;
	uint32_t flags;
	uint32_t dictlen;
	char     path[0];
	char     bname[0];
	char     dict[0];
} __attribute__((packed)) gf_fop_lookup_req_t;
typedef struct {
	struct gf_stat stat;
	uint32_t       dict_len;
	char           dict[0];
} __attribute__((packed)) gf_fop_lookup_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint32_t flags;
	uint32_t count;
	char     buf[0];
} __attribute__((packed)) gf_fop_setdents_req_t;
typedef struct { } __attribute__((packed)) gf_fop_setdents_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t  fd;
	uint64_t offset;
	uint32_t size;
	uint32_t flags;
} __attribute__((packed)) gf_fop_getdents_req_t;
typedef struct {
	uint32_t count;
	char buf[0];
} __attribute__((packed)) gf_fop_getdents_rsp_t;


typedef struct {
	uint64_t  ino;
	uint32_t  flag;
	char      path[0];
} __attribute__((packed)) gf_fop_checksum_req_t;
typedef struct {
	unsigned char fchecksum[0];
	unsigned char dchecksum[0];
} __attribute__((packed)) gf_fop_checksum_rsp_t;


typedef struct {
	uint64_t  ino;
	int32_t   timeout;
} __attribute__((packed)) gf_fop_lock_notify_req_t;
typedef struct { } __attribute__((packed)) gf_fop_lock_notify_rsp_t;


typedef struct {
	int64_t   fd;
	int32_t   timeout;
} __attribute__((packed)) gf_fop_lock_fnotify_req_t;
typedef struct { } __attribute__((packed)) gf_fop_lock_fnotify_rsp_t;


typedef struct {
	char name[0];
} __attribute__((packed)) gf_mop_lock_req_t;
typedef struct {} __attribute__((packed)) gf_mop_lock_rsp_t;

typedef struct {
	char name[0];
} __attribute__((packed)) gf_mop_unlock_req_t;
typedef struct {} __attribute__((packed)) gf_mop_unlock_rsp_t;

typedef struct {
	char pattern[0];
} __attribute__((packed)) gf_mop_listlocks_req_t;
typedef struct {} __attribute__((packed)) gf_mop_listlocks_rsp_t;

typedef struct {
	uint32_t  flags;
} __attribute__((packed)) gf_mop_stats_req_t;
typedef struct {
	char buf[0];
} __attribute__((packed)) gf_mop_stats_rsp_t;

typedef struct {
	uint32_t flags;
	uint32_t keylen;
	char     key[0];
} __attribute__((packed)) gf_mop_getspec_req_t;
typedef struct {
	char spec[0];
} __attribute__((packed)) gf_mop_getspec_rsp_t;


typedef struct {
        uint32_t msglen;
	char     msg[0];
} __attribute__((packed)) gf_mop_log_req_t;
typedef struct {
} __attribute__((packed)) gf_mop_log_rsp_t;


typedef struct {
	uint32_t dict_len;
	char buf[0];
} __attribute__((packed)) gf_mop_setvolume_req_t;
typedef struct {
	uint32_t dict_len;
	char buf[0];
} __attribute__((packed)) gf_mop_setvolume_rsp_t;


typedef struct {
} __attribute__((packed)) gf_mop_ping_req_t;
typedef struct {
} __attribute__((packed)) gf_mop_ping_rsp_t;


typedef struct {
	uint64_t ino;
	int64_t fd;