From 7c2379d458e36127775650487aa5005950e108b6 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sat, 12 Feb 2022 01:30:50 +0300 Subject: [PATCH] Simplified NFS proxy based on own NFS/XDR implementation --- README-ru.md | 43 +- README.md | 44 +- cpp-btree | 2 +- debian/vitastor-client.install | 1 + rpm/vitastor-el7.spec | 1 + rpm/vitastor-el8.spec | 1 + src/CMakeLists.txt | 15 + src/cli_create.cpp | 12 +- src/cli_modify.cpp | 4 +- src/cluster_client.cpp | 5 + src/cluster_client.h | 2 + src/etcd_state_client.cpp | 26 +- src/etcd_state_client.h | 4 + src/nfs/nfs.h | 1690 ++++++++++++++++++ src/nfs/nfs.x | 1380 +++++++++++++++ src/nfs/nfs_xdr.cpp | 2954 ++++++++++++++++++++++++++++++++ src/nfs/portmap.h | 190 ++ src/nfs/portmap.x | 168 ++ src/nfs/portmap_xdr.cpp | 406 +++++ src/nfs/rpc.h | 160 ++ src/nfs/rpc.x | 113 ++ src/nfs/rpc_impl.h | 43 + src/nfs/rpc_xdr.cpp | 253 +++ src/nfs/run-rpcgen.sh | 48 + src/nfs/xdr_impl.cpp | 107 ++ src/nfs/xdr_impl.h | 83 + src/nfs/xdr_impl_inline.h | 309 ++++ src/nfs_conn.cpp | 1297 ++++++++++++++ src/nfs_portmap.cpp | 184 ++ src/nfs_portmap.h | 39 + src/nfs_proxy.cpp | 972 +++++++++++ src/nfs_proxy.h | 124 ++ src/sha256.c | 158 ++ src/sha256.h | 41 + 34 files changed, 10868 insertions(+), 11 deletions(-) create mode 100644 src/nfs/nfs.h create mode 100644 src/nfs/nfs.x create mode 100644 src/nfs/nfs_xdr.cpp create mode 100644 src/nfs/portmap.h create mode 100644 src/nfs/portmap.x create mode 100644 src/nfs/portmap_xdr.cpp create mode 100644 src/nfs/rpc.h create mode 100644 src/nfs/rpc.x create mode 100644 src/nfs/rpc_impl.h create mode 100644 src/nfs/rpc_xdr.cpp create mode 100755 src/nfs/run-rpcgen.sh create mode 100644 src/nfs/xdr_impl.cpp create mode 100644 src/nfs/xdr_impl.h create mode 100644 src/nfs/xdr_impl_inline.h create mode 100644 src/nfs_conn.cpp create mode 100644 src/nfs_portmap.cpp create mode 100644 src/nfs_portmap.h create mode 100644 src/nfs_proxy.cpp create mode 100644 src/nfs_proxy.h create mode 100644 src/sha256.c create mode 100644 src/sha256.h diff --git a/README-ru.md b/README-ru.md index 160cb27b5..622091f69 100644 --- a/README-ru.md +++ b/README-ru.md @@ -52,6 +52,7 @@ Vitastor на данный момент находится в статусе п - Слияние снапшотов (vitastor-cli {snap-rm,flatten,merge}) - Консольный интерфейс для управления образами (vitastor-cli {ls,create,modify}) - Плагин для Proxmox +- Упрощённая NFS-прокси для эмуляции файлового доступа к образам (подходит для VMWare) ## Планы развития @@ -59,7 +60,6 @@ Vitastor на данный момент находится в статусе п - Другие инструменты администрирования - Плагины для OpenNebula и других облачных систем - iSCSI-прокси -- Упрощённый NFS прокси - Более быстрое переключение при отказах - Фоновая проверка целостности без контрольных сумм (сверка реплик) - Контрольные суммы @@ -530,9 +530,48 @@ vitastor-nbd map --etcd_address 10.115.0.10:2379/v3 --image testimg Для обращения по номеру инода, аналогично другим командам, можно использовать опции `--pool --inode --size ` вместо `--image testimg`. +### NFS + +В Vitastor реализована упрощённая NFS 3.0 прокси для эмуляции файлового доступа к образам. +Это не полноценная файловая система, т.к. метаданные всех файлов (образов) сохраняются +в etcd и всё время хранятся в оперативной памяти - то есть, положить туда много файлов +не получится. + +Однако в качестве способа доступа к образам виртуальных машин NFS прокси прекрасно подходит +и позволяет подключить Vitastor, например, к VMWare. + +При этом, если вы используете режим immediate_commit=all (для SSD с конденсаторами или HDD +с отключённым кэшем), то NFS-сервер не имеет состояния и вы можете свободно поднять +его в нескольких экземплярах и использовать поверх них сетевой балансировщик нагрузки или +схему с отказоустойчивостью. + +Использование vitastor-nfs: + +``` +vitastor-nfs [--etcd_address ADDR] [ДРУГИЕ ОПЦИИ] + +--subdir экспортировать "поддиректорию" - образы с префиксом имени / (по умолчанию пусто - экспортировать все образы) +--portmap 0 отключить сервис portmap/rpcbind на порту 111 (по умолчанию включён и требует root привилегий) +--bind принимать соединения по адресу (по умолчанию 0.0.0.0 - на всех) +--nfspath установить путь NFS-экспорта в (по умолчанию /) +--port использовать порт для NFS-сервисов (по умолчанию 2049) +--pool исползовать пул для новых образов (обязательно, если пул в кластере не один) +--foreground 1 не уходить в фон после запуска +``` + +Пример монтирования Vitastor через NFS: + +``` +vitastor-nfs --etcd_address 192.168.5.10:2379 --portmap 0 --port 2050 --pool testpool +``` + +``` +mount localhost:/ /mnt/ -o port=2050,mountport=2050,nfsvers=3,soft,nolock,tcp +``` + ### Kubernetes -У Vitastor есть CSI-плагин для Kubernetes, поддерживающий RWO-тома. +У Vitastor есть CSI-плагин для Kubernetes, поддерживающий RWO, а также блочные RWX, тома. Для установки возьмите манифесты из директории [csi/deploy/](csi/deploy/), поместите вашу конфигурацию подключения к Vitastor в [csi/deploy/001-csi-config-map.yaml](001-csi-config-map.yaml), diff --git a/README.md b/README.md index 0490e7fce..f5f842282 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ breaking changes in the future. However, the following is implemented: - Snapshot merge tool (vitastor-cli {snap-rm,flatten,merge}) - Image management CLI (vitastor-cli {ls,create,modify}) - Proxmox storage plugin +- Simplified NFS proxy for file-based image access emulation (suitable for VMWare) ## Roadmap @@ -53,7 +54,6 @@ breaking changes in the future. However, the following is implemented: - Other administrative tools - Plugins for OpenNebula and other cloud systems - iSCSI proxy -- Simplified NFS proxy - Faster failover - Scrubbing without checksums (verification of replicas) - Checksums @@ -479,9 +479,49 @@ It will output the device name, like /dev/nbd0 which you can then format and mou Again, you can use `--pool --inode --size ` insteaf of `--image ` if you want. +### NFS + +Vitastor has a simplified NFS 3.0 proxy for file-based image access emulation. It's not +suitable as a full-featured file system, at least because all file/image metadata is stored +in etcd and kept in memory all the time - thus you can't put a lot of files in it. + +However, NFS proxy is totally fine as a method to provide VM image access and allows to +plug Vitastor into, for example, VMWare. It's important to note that for VMWare it's a much +better access method than iSCSI, because with iSCSI we'd have to put all VM images into one +Vitastor image exported as a LUN to VMWare and formatted with VMFS. VMWare doesn't use VMFS +over NFS. + +NFS proxy is stateless if you use immediate_commit=all mode (for SSD with capacitors or +HDDs with disabled cache), so you can run multiple NFS proxies and use a network load +balancer or any failover method you want to in that case. + +vitastor-nfs usage: + +``` +vitastor-nfs [--etcd_address ADDR] [OTHER OPTIONS] + +--subdir export images prefixed / (default empty - export all images) +--portmap 0 do not listen on port 111 (portmap/rpcbind, requires root) +--bind bind service to address (default 0.0.0.0) +--nfspath set NFS export path to (default is /) +--port use port for NFS services (default is 2049) +--pool use as default pool for new files (images) +--foreground 1 stay in foreground, do not daemonize +``` + +Example start and mount commands: + +``` +vitastor-nfs --etcd_address 192.168.5.10:2379 --portmap 0 --port 2050 --pool testpool +``` + +``` +mount localhost:/ /mnt/ -o port=2050,mountport=2050,nfsvers=3,soft,nolock,tcp +``` + ### Kubernetes -Vitastor has a CSI plugin for Kubernetes which supports RWO volumes. +Vitastor has a CSI plugin for Kubernetes which supports RWO (and block RWX) volumes. To deploy it, take manifests from [csi/deploy/](csi/deploy/) directory, put your Vitastor configuration in [csi/deploy/001-csi-config-map.yaml](001-csi-config-map.yaml), diff --git a/cpp-btree b/cpp-btree index 6e2014640..903ec858b 160000 --- a/cpp-btree +++ b/cpp-btree @@ -1 +1 @@ -Subproject commit 6e201464060ace53db809d65da7b0e2800673f8f +Subproject commit 903ec858bc8ab00fc0fbd44c23f0ab7770772353 diff --git a/debian/vitastor-client.install b/debian/vitastor-client.install index 177219282..49ca5dadb 100644 --- a/debian/vitastor-client.install +++ b/debian/vitastor-client.install @@ -2,5 +2,6 @@ usr/bin/vita usr/bin/vitastor-cli usr/bin/vitastor-rm usr/bin/vitastor-nbd +usr/bin/vitastor-nfs usr/lib/*/libvitastor*.so* mon/make-osd.sh /usr/lib/vitastor diff --git a/rpm/vitastor-el7.spec b/rpm/vitastor-el7.spec index ddda88098..c82781ac0 100644 --- a/rpm/vitastor-el7.spec +++ b/rpm/vitastor-el7.spec @@ -119,6 +119,7 @@ cp -r mon %buildroot/usr/lib/vitastor %files -n vitastor-client %_bindir/vitastor-nbd +%_bindir/vitastor-nfs %_bindir/vitastor-cli %_bindir/vitastor-rm %_bindir/vita diff --git a/rpm/vitastor-el8.spec b/rpm/vitastor-el8.spec index b24bba176..02d23f5bd 100644 --- a/rpm/vitastor-el8.spec +++ b/rpm/vitastor-el8.spec @@ -116,6 +116,7 @@ cp -r mon %buildroot/usr/lib/vitastor %files -n vitastor-client %_bindir/vitastor-nbd +%_bindir/vitastor-nfs %_bindir/vitastor-cli %_bindir/vitastor-rm %_bindir/vita diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1720497d1..979240aeb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -164,6 +164,21 @@ target_link_libraries(vitastor-nbd vitastor_client ) +# vitastor-nfs +add_executable(vitastor-nfs + nfs_proxy.cpp + nfs_conn.cpp + nfs_portmap.cpp + sha256.c + nfs/xdr_impl.cpp + nfs/rpc_xdr.cpp + nfs/portmap_xdr.cpp + nfs/nfs_xdr.cpp +) +target_link_libraries(vitastor-nfs + vitastor_client +) + # vitastor-cli add_executable(vitastor-cli cli.cpp diff --git a/src/cli_create.cpp b/src/cli_create.cpp index 15f5ce343..4fafcdddb 100644 --- a/src/cli_create.cpp +++ b/src/cli_create.cpp @@ -25,7 +25,9 @@ struct image_creator_t pool_id_t new_pool_id = 0; std::string new_pool_name; std::string image_name, new_snap, new_parent; + json11::Json new_meta; uint64_t size; + bool force_size = false; pool_id_t old_pool_id = 0; inode_t new_parent_id = 0; @@ -137,7 +139,7 @@ struct image_creator_t state = 100; return; } - if (!size) + if (!size && !force_size) { result = (cli_result_t){ .err = EINVAL, .text = "Image size is missing" }; state = 100; @@ -387,6 +389,7 @@ resume_3: .size = size, .parent_id = (new_snap != "" ? INODE_WITH_POOL(old_pool_id, old_id) : new_parent_id), .readonly = false, + .meta = new_meta, }; json11::Json::array checks = json11::Json::array { json11::Json::object { @@ -538,6 +541,11 @@ std::function cli_tool_t::start_create(json11::Json cfg) image_creator->image_name = cfg["image"].string_value(); image_creator->new_pool_id = cfg["pool"].uint64_value(); image_creator->new_pool_name = cfg["pool"].string_value(); + image_creator->force_size = cfg["force_size"].bool_value(); + if (cfg["image_meta"].is_object()) + { + image_creator->new_meta = cfg["image-meta"]; + } if (cfg["snapshot"].string_value() != "") { image_creator->new_snap = cfg["snapshot"].string_value(); @@ -554,7 +562,7 @@ std::function cli_tool_t::start_create(json11::Json cfg) return true; }; } - if (image_creator->size % 4096) + if ((image_creator->size % 4096) && !cfg["force_size"].bool_value()) { delete image_creator; return [](cli_result_t & result) diff --git a/src/cli_modify.cpp b/src/cli_modify.cpp index c721ed07a..86c3ff07a 100644 --- a/src/cli_modify.cpp +++ b/src/cli_modify.cpp @@ -81,14 +81,14 @@ struct image_changer_t } if ((!set_readwrite || !cfg.readonly) && (!set_readonly || cfg.readonly) && - (!new_size || cfg.size == new_size) && + (!new_size && !force_size || cfg.size == new_size) && (new_name == "" || new_name == image_name)) { result = (cli_result_t){ .text = "No change" }; state = 100; return; } - if (new_size != 0) + if (new_size != 0 || force_size) { if (cfg.size >= new_size) { diff --git a/src/cluster_client.cpp b/src/cluster_client.cpp index d3e970b3b..6030f8fbb 100644 --- a/src/cluster_client.cpp +++ b/src/cluster_client.cpp @@ -374,6 +374,11 @@ void cluster_client_t::on_change_hook(std::map & changes continue_ops(); } +bool cluster_client_t::get_immediate_commit() +{ + return immediate_commit; +} + void cluster_client_t::on_change_osd_state_hook(uint64_t peer_osd) { if (msgr.wanted_peers.find(peer_osd) != msgr.wanted_peers.end()) diff --git a/src/cluster_client.h b/src/cluster_client.h index 77b1b63d1..0dae2bb24 100644 --- a/src/cluster_client.h +++ b/src/cluster_client.h @@ -118,6 +118,8 @@ public: bool is_ready(); void on_ready(std::function fn); + bool get_immediate_commit(); + static void copy_write(cluster_op_t *op, std::map & dirty_buffers); void continue_ops(bool up_retry = false); inode_list_t *list_inode_start(inode_t inode, diff --git a/src/etcd_state_client.cpp b/src/etcd_state_client.cpp index 8b54c91e3..50c152b64 100644 --- a/src/etcd_state_client.cpp +++ b/src/etcd_state_client.cpp @@ -338,9 +338,14 @@ void etcd_state_client_t::start_etcd_watcher() { if (data["result"]["created"].bool_value()) { - if (etcd_watches_initialised == 3 && this->log_level > 0) + uint64_t watch_id = data["result"]["watch_id"].uint64_value(); + if (watch_id == ETCD_CONFIG_WATCH_ID || + watch_id == ETCD_PG_STATE_WATCH_ID || + watch_id == ETCD_PG_HISTORY_WATCH_ID || + watch_id == ETCD_OSD_STATE_WATCH_ID) + etcd_watches_initialised++; + if (etcd_watches_initialised == 4 && this->log_level > 0) fprintf(stderr, "Successfully subscribed to etcd at %s\n", selected_etcd_address.c_str()); - etcd_watches_initialised++; } if (data["result"]["canceled"].bool_value()) { @@ -469,6 +474,10 @@ void etcd_state_client_t::start_etcd_watcher() { "progress_notify", true }, } } }).dump()); + if (on_start_watcher_hook) + { + on_start_watcher_hook(etcd_watch_ws); + } if (ws_keepalive_timer < 0) { ws_keepalive_timer = tfd->set_timer(etcd_ws_keepalive_interval*1000, true, [this](int) @@ -954,6 +963,10 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv) } if (!value.is_object()) { + if (on_inode_change_hook != NULL) + { + on_inode_change_hook(inode_num, true); + } this->inode_config.erase(inode_num); } else @@ -981,6 +994,7 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv) .size = value["size"].uint64_value(), .parent_id = parent_inode_num, .readonly = value["readonly"].bool_value(), + .meta = value["meta"], .mod_revision = kv.mod_revision, }); } @@ -1002,6 +1016,10 @@ void etcd_state_client_t::insert_inode_config(const inode_config_t & cfg) } } } + if (on_inode_change_hook != NULL) + { + on_inode_change_hook(cfg.num, false); + } } inode_watch_t* etcd_state_client_t::watch_inode(std::string name) @@ -1046,6 +1064,10 @@ json11::Json::object etcd_state_client_t::serialize_inode_cfg(inode_config_t *cf { new_cfg["readonly"] = true; } + if (cfg->meta.is_object()) + { + new_cfg["meta"] = cfg->meta; + } return new_cfg; } diff --git a/src/etcd_state_client.h b/src/etcd_state_client.h index 9c07bf4d0..6a2099ed3 100644 --- a/src/etcd_state_client.h +++ b/src/etcd_state_client.h @@ -56,6 +56,8 @@ struct inode_config_t uint64_t size; inode_t parent_id; bool readonly; + // Arbitrary metadata + json11::Json meta; // Change revision of the metadata in etcd uint64_t mod_revision; }; @@ -109,6 +111,8 @@ public: std::function on_change_pg_history_hook; std::function on_change_osd_state_hook; std::function on_reload_hook; + std::function on_inode_change_hook; + std::function on_start_watcher_hook; json11::Json::object serialize_inode_cfg(inode_config_t *cfg); etcd_kv_t parse_etcd_kv(const json11::Json & kv_json); diff --git a/src/nfs/nfs.h b/src/nfs/nfs.h new file mode 100644 index 000000000..685310ec0 --- /dev/null +++ b/src/nfs/nfs.h @@ -0,0 +1,1690 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _NFS_H_RPCGEN +#define _NFS_H_RPCGEN + +#include "xdr_impl.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFS3_FHSIZE 64 +#define NFS3_WRITEVERFSIZE 8 +#define NFS3_CREATEVERFSIZE 8 +#define NFS3_COOKIEVERFSIZE 8 + +typedef char cookieverf3[NFS3_COOKIEVERFSIZE]; + +typedef uint64_t cookie3; + +typedef xdr_string_t nfs_fh3; + +typedef xdr_string_t filename3; + +struct diropargs3 { + nfs_fh3 dir; + filename3 name; +}; +typedef struct diropargs3 diropargs3; + +enum ftype3 { + NF3REG = 1, + NF3DIR = 2, + NF3BLK = 3, + NF3CHR = 4, + NF3LNK = 5, + NF3SOCK = 6, + NF3FIFO = 7, +}; +typedef enum ftype3 ftype3; + +typedef u_int mode3; + +typedef u_int uid3; + +typedef u_int gid3; + +typedef uint64_t size3; + +typedef uint64_t fileid3; + +struct specdata3 { + u_int specdata1; + u_int specdata2; +}; +typedef struct specdata3 specdata3; + +struct nfstime3 { + u_int seconds; + u_int nseconds; +}; +typedef struct nfstime3 nfstime3; + +struct fattr3 { + ftype3 type; + mode3 mode; + u_int nlink; + uid3 uid; + gid3 gid; + size3 size; + size3 used; + specdata3 rdev; + uint64_t fsid; + fileid3 fileid; + nfstime3 atime; + nfstime3 mtime; + nfstime3 ctime; +}; +typedef struct fattr3 fattr3; + +struct post_op_attr { + bool_t attributes_follow; + union { + fattr3 attributes; + }; +}; +typedef struct post_op_attr post_op_attr; + +enum nfsstat3 { + NFS3_OK = 0, + NFS3ERR_PERM = 1, + NFS3ERR_NOENT = 2, + NFS3ERR_IO = 5, + NFS3ERR_NXIO = 6, + NFS3ERR_ACCES = 13, + NFS3ERR_EXIST = 17, + NFS3ERR_XDEV = 18, + NFS3ERR_NODEV = 19, + NFS3ERR_NOTDIR = 20, + NFS3ERR_ISDIR = 21, + NFS3ERR_INVAL = 22, + NFS3ERR_FBIG = 27, + NFS3ERR_NOSPC = 28, + NFS3ERR_ROFS = 30, + NFS3ERR_MLINK = 31, + NFS3ERR_NAMETOOLONG = 63, + NFS3ERR_NOTEMPTY = 66, + NFS3ERR_DQUOT = 69, + NFS3ERR_STALE = 70, + NFS3ERR_REMOTE = 71, + NFS3ERR_BADHANDLE = 10001, + NFS3ERR_NOT_SYNC = 10002, + NFS3ERR_BAD_COOKIE = 10003, + NFS3ERR_NOTSUPP = 10004, + NFS3ERR_TOOSMALL = 10005, + NFS3ERR_SERVERFAULT = 10006, + NFS3ERR_BADTYPE = 10007, + NFS3ERR_JUKEBOX = 10008, +}; +typedef enum nfsstat3 nfsstat3; + +enum stable_how { + UNSTABLE = 0, + DATA_SYNC = 1, + FILE_SYNC = 2, +}; +typedef enum stable_how stable_how; + +typedef uint64_t offset3; + +typedef u_int count3; + +struct wcc_attr { + size3 size; + nfstime3 mtime; + nfstime3 ctime; +}; +typedef struct wcc_attr wcc_attr; + +struct pre_op_attr { + bool_t attributes_follow; + union { + wcc_attr attributes; + }; +}; +typedef struct pre_op_attr pre_op_attr; + +struct wcc_data { + pre_op_attr before; + post_op_attr after; +}; +typedef struct wcc_data wcc_data; + +struct WRITE3args { + nfs_fh3 file; + offset3 offset; + count3 count; + stable_how stable; + xdr_string_t data; +}; +typedef struct WRITE3args WRITE3args; + +typedef char writeverf3[NFS3_WRITEVERFSIZE]; + +struct WRITE3resok { + wcc_data file_wcc; + count3 count; + stable_how committed; + writeverf3 verf; +}; +typedef struct WRITE3resok WRITE3resok; + +struct WRITE3resfail { + wcc_data file_wcc; +}; +typedef struct WRITE3resfail WRITE3resfail; + +struct WRITE3res { + nfsstat3 status; + union { + WRITE3resok resok; + WRITE3resfail resfail; + }; +}; +typedef struct WRITE3res WRITE3res; + +struct LOOKUP3args { + diropargs3 what; +}; +typedef struct LOOKUP3args LOOKUP3args; + +struct LOOKUP3resok { + nfs_fh3 object; + post_op_attr obj_attributes; + post_op_attr dir_attributes; +}; +typedef struct LOOKUP3resok LOOKUP3resok; + +struct LOOKUP3resfail { + post_op_attr dir_attributes; +}; +typedef struct LOOKUP3resfail LOOKUP3resfail; + +struct LOOKUP3res { + nfsstat3 status; + union { + LOOKUP3resok resok; + LOOKUP3resfail resfail; + }; +}; +typedef struct LOOKUP3res LOOKUP3res; + +struct COMMIT3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; +typedef struct COMMIT3args COMMIT3args; + +struct COMMIT3resok { + wcc_data file_wcc; + writeverf3 verf; +}; +typedef struct COMMIT3resok COMMIT3resok; + +struct COMMIT3resfail { + wcc_data file_wcc; +}; +typedef struct COMMIT3resfail COMMIT3resfail; + +struct COMMIT3res { + nfsstat3 status; + union { + COMMIT3resok resok; + COMMIT3resfail resfail; + }; +}; +typedef struct COMMIT3res COMMIT3res; +#define ACCESS3_READ 0x0001 +#define ACCESS3_LOOKUP 0x0002 +#define ACCESS3_MODIFY 0x0004 +#define ACCESS3_EXTEND 0x0008 +#define ACCESS3_DELETE 0x0010 +#define ACCESS3_EXECUTE 0x0020 + +struct ACCESS3args { + nfs_fh3 object; + u_int access; +}; +typedef struct ACCESS3args ACCESS3args; + +struct ACCESS3resok { + post_op_attr obj_attributes; + u_int access; +}; +typedef struct ACCESS3resok ACCESS3resok; + +struct ACCESS3resfail { + post_op_attr obj_attributes; +}; +typedef struct ACCESS3resfail ACCESS3resfail; + +struct ACCESS3res { + nfsstat3 status; + union { + ACCESS3resok resok; + ACCESS3resfail resfail; + }; +}; +typedef struct ACCESS3res ACCESS3res; + +struct GETATTR3args { + nfs_fh3 object; +}; +typedef struct GETATTR3args GETATTR3args; + +struct GETATTR3resok { + fattr3 obj_attributes; +}; +typedef struct GETATTR3resok GETATTR3resok; + +struct GETATTR3res { + nfsstat3 status; + union { + GETATTR3resok resok; + }; +}; +typedef struct GETATTR3res GETATTR3res; + +enum time_how { + DONT_CHANGE = 0, + SET_TO_SERVER_TIME = 1, + SET_TO_CLIENT_TIME = 2, +}; +typedef enum time_how time_how; + +struct set_mode3 { + bool_t set_it; + union { + mode3 mode; + }; +}; +typedef struct set_mode3 set_mode3; + +struct set_uid3 { + bool_t set_it; + union { + uid3 uid; + }; +}; +typedef struct set_uid3 set_uid3; + +struct set_gid3 { + bool_t set_it; + union { + gid3 gid; + }; +}; +typedef struct set_gid3 set_gid3; + +struct set_size3 { + bool_t set_it; + union { + size3 size; + }; +}; +typedef struct set_size3 set_size3; + +struct set_atime { + time_how set_it; + union { + nfstime3 atime; + }; +}; +typedef struct set_atime set_atime; + +struct set_mtime { + time_how set_it; + union { + nfstime3 mtime; + }; +}; +typedef struct set_mtime set_mtime; + +struct sattr3 { + set_mode3 mode; + set_uid3 uid; + set_gid3 gid; + set_size3 size; + set_atime atime; + set_mtime mtime; +}; +typedef struct sattr3 sattr3; + +enum createmode3 { + NFS_UNCHECKED = 0, + NFS_GUARDED = 1, + NFS_EXCLUSIVE = 2, +}; +typedef enum createmode3 createmode3; + +typedef char createverf3[NFS3_CREATEVERFSIZE]; + +struct createhow3 { + createmode3 mode; + union { + sattr3 obj_attributes; + sattr3 g_obj_attributes; + createverf3 verf; + }; +}; +typedef struct createhow3 createhow3; + +struct CREATE3args { + diropargs3 where; + createhow3 how; +}; +typedef struct CREATE3args CREATE3args; + +struct post_op_fh3 { + bool_t handle_follows; + union { + nfs_fh3 handle; + }; +}; +typedef struct post_op_fh3 post_op_fh3; + +struct CREATE3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; +typedef struct CREATE3resok CREATE3resok; + +struct CREATE3resfail { + wcc_data dir_wcc; +}; +typedef struct CREATE3resfail CREATE3resfail; + +struct CREATE3res { + nfsstat3 status; + union { + CREATE3resok resok; + CREATE3resfail resfail; + }; +}; +typedef struct CREATE3res CREATE3res; + +struct REMOVE3args { + diropargs3 object; +}; +typedef struct REMOVE3args REMOVE3args; + +struct REMOVE3resok { + wcc_data dir_wcc; +}; +typedef struct REMOVE3resok REMOVE3resok; + +struct REMOVE3resfail { + wcc_data dir_wcc; +}; +typedef struct REMOVE3resfail REMOVE3resfail; + +struct REMOVE3res { + nfsstat3 status; + union { + REMOVE3resok resok; + REMOVE3resfail resfail; + }; +}; +typedef struct REMOVE3res REMOVE3res; + +struct READ3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; +typedef struct READ3args READ3args; + +struct READ3resok { + post_op_attr file_attributes; + count3 count; + bool_t eof; + xdr_string_t data; +}; +typedef struct READ3resok READ3resok; + +struct READ3resfail { + post_op_attr file_attributes; +}; +typedef struct READ3resfail READ3resfail; + +struct READ3res { + nfsstat3 status; + union { + READ3resok resok; + READ3resfail resfail; + }; +}; +typedef struct READ3res READ3res; +#define FSF3_LINK 0x0001 +#define FSF3_SYMLINK 0x0002 +#define FSF3_HOMOGENEOUS 0x0008 +#define FSF3_CANSETTIME 0x0010 + +struct FSINFO3args { + nfs_fh3 fsroot; +}; +typedef struct FSINFO3args FSINFO3args; + +struct FSINFO3resok { + post_op_attr obj_attributes; + u_int rtmax; + u_int rtpref; + u_int rtmult; + u_int wtmax; + u_int wtpref; + u_int wtmult; + u_int dtpref; + size3 maxfilesize; + nfstime3 time_delta; + u_int properties; +}; +typedef struct FSINFO3resok FSINFO3resok; + +struct FSINFO3resfail { + post_op_attr obj_attributes; +}; +typedef struct FSINFO3resfail FSINFO3resfail; + +struct FSINFO3res { + nfsstat3 status; + union { + FSINFO3resok resok; + FSINFO3resfail resfail; + }; +}; +typedef struct FSINFO3res FSINFO3res; + +struct FSSTAT3args { + nfs_fh3 fsroot; +}; +typedef struct FSSTAT3args FSSTAT3args; + +struct FSSTAT3resok { + post_op_attr obj_attributes; + size3 tbytes; + size3 fbytes; + size3 abytes; + size3 tfiles; + size3 ffiles; + size3 afiles; + u_int invarsec; +}; +typedef struct FSSTAT3resok FSSTAT3resok; + +struct FSSTAT3resfail { + post_op_attr obj_attributes; +}; +typedef struct FSSTAT3resfail FSSTAT3resfail; + +struct FSSTAT3res { + nfsstat3 status; + union { + FSSTAT3resok resok; + FSSTAT3resfail resfail; + }; +}; +typedef struct FSSTAT3res FSSTAT3res; + +struct PATHCONF3args { + nfs_fh3 object; +}; +typedef struct PATHCONF3args PATHCONF3args; + +struct PATHCONF3resok { + post_op_attr obj_attributes; + u_int linkmax; + u_int name_max; + bool_t no_trunc; + bool_t chown_restricted; + bool_t case_insensitive; + bool_t case_preserving; +}; +typedef struct PATHCONF3resok PATHCONF3resok; + +struct PATHCONF3resfail { + post_op_attr obj_attributes; +}; +typedef struct PATHCONF3resfail PATHCONF3resfail; + +struct PATHCONF3res { + nfsstat3 status; + union { + PATHCONF3resok resok; + PATHCONF3resfail resfail; + }; +}; +typedef struct PATHCONF3res PATHCONF3res; + +typedef xdr_string_t nfspath3; + +struct symlinkdata3 { + sattr3 symlink_attributes; + nfspath3 symlink_data; +}; +typedef struct symlinkdata3 symlinkdata3; + +struct SYMLINK3args { + diropargs3 where; + symlinkdata3 symlink; +}; +typedef struct SYMLINK3args SYMLINK3args; + +struct SYMLINK3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; +typedef struct SYMLINK3resok SYMLINK3resok; + +struct SYMLINK3resfail { + wcc_data dir_wcc; +}; +typedef struct SYMLINK3resfail SYMLINK3resfail; + +struct SYMLINK3res { + nfsstat3 status; + union { + SYMLINK3resok resok; + SYMLINK3resfail resfail; + }; +}; +typedef struct SYMLINK3res SYMLINK3res; + +struct READLINK3args { + nfs_fh3 symlink; +}; +typedef struct READLINK3args READLINK3args; + +struct READLINK3resok { + post_op_attr symlink_attributes; + nfspath3 data; +}; +typedef struct READLINK3resok READLINK3resok; + +struct READLINK3resfail { + post_op_attr symlink_attributes; +}; +typedef struct READLINK3resfail READLINK3resfail; + +struct READLINK3res { + nfsstat3 status; + union { + READLINK3resok resok; + READLINK3resfail resfail; + }; +}; +typedef struct READLINK3res READLINK3res; + +struct devicedata3 { + sattr3 dev_attributes; + specdata3 spec; +}; +typedef struct devicedata3 devicedata3; + +struct mknoddata3 { + ftype3 type; + union { + devicedata3 chr_device; + devicedata3 blk_device; + sattr3 sock_attributes; + sattr3 pipe_attributes; + }; +}; +typedef struct mknoddata3 mknoddata3; + +struct MKNOD3args { + diropargs3 where; + mknoddata3 what; +}; +typedef struct MKNOD3args MKNOD3args; + +struct MKNOD3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; +typedef struct MKNOD3resok MKNOD3resok; + +struct MKNOD3resfail { + wcc_data dir_wcc; +}; +typedef struct MKNOD3resfail MKNOD3resfail; + +struct MKNOD3res { + nfsstat3 status; + union { + MKNOD3resok resok; + MKNOD3resfail resfail; + }; +}; +typedef struct MKNOD3res MKNOD3res; + +struct MKDIR3args { + diropargs3 where; + sattr3 attributes; +}; +typedef struct MKDIR3args MKDIR3args; + +struct MKDIR3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; +typedef struct MKDIR3resok MKDIR3resok; + +struct MKDIR3resfail { + wcc_data dir_wcc; +}; +typedef struct MKDIR3resfail MKDIR3resfail; + +struct MKDIR3res { + nfsstat3 status; + union { + MKDIR3resok resok; + MKDIR3resfail resfail; + }; +}; +typedef struct MKDIR3res MKDIR3res; + +struct RMDIR3args { + diropargs3 object; +}; +typedef struct RMDIR3args RMDIR3args; + +struct RMDIR3resok { + wcc_data dir_wcc; +}; +typedef struct RMDIR3resok RMDIR3resok; + +struct RMDIR3resfail { + wcc_data dir_wcc; +}; +typedef struct RMDIR3resfail RMDIR3resfail; + +struct RMDIR3res { + nfsstat3 status; + union { + RMDIR3resok resok; + RMDIR3resfail resfail; + }; +}; +typedef struct RMDIR3res RMDIR3res; + +struct RENAME3args { + diropargs3 from; + diropargs3 to; +}; +typedef struct RENAME3args RENAME3args; + +struct RENAME3resok { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; +typedef struct RENAME3resok RENAME3resok; + +struct RENAME3resfail { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; +typedef struct RENAME3resfail RENAME3resfail; + +struct RENAME3res { + nfsstat3 status; + union { + RENAME3resok resok; + RENAME3resfail resfail; + }; +}; +typedef struct RENAME3res RENAME3res; + +struct READDIRPLUS3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 dircount; + count3 maxcount; +}; +typedef struct READDIRPLUS3args READDIRPLUS3args; + +struct entryplus3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + post_op_attr name_attributes; + post_op_fh3 name_handle; + struct entryplus3 *nextentry; +}; +typedef struct entryplus3 entryplus3; + +struct dirlistplus3 { + entryplus3 *entries; + bool_t eof; +}; +typedef struct dirlistplus3 dirlistplus3; + +struct READDIRPLUS3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlistplus3 reply; +}; +typedef struct READDIRPLUS3resok READDIRPLUS3resok; + +struct READDIRPLUS3resfail { + post_op_attr dir_attributes; +}; +typedef struct READDIRPLUS3resfail READDIRPLUS3resfail; + +struct READDIRPLUS3res { + nfsstat3 status; + union { + READDIRPLUS3resok resok; + READDIRPLUS3resfail resfail; + }; +}; +typedef struct READDIRPLUS3res READDIRPLUS3res; + +struct READDIR3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 count; +}; +typedef struct READDIR3args READDIR3args; + +struct entry3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + struct entry3 *nextentry; +}; +typedef struct entry3 entry3; + +struct dirlist3 { + entry3 *entries; + bool_t eof; +}; +typedef struct dirlist3 dirlist3; + +struct READDIR3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlist3 reply; +}; +typedef struct READDIR3resok READDIR3resok; + +struct READDIR3resfail { + post_op_attr dir_attributes; +}; +typedef struct READDIR3resfail READDIR3resfail; + +struct READDIR3res { + nfsstat3 status; + union { + READDIR3resok resok; + READDIR3resfail resfail; + }; +}; +typedef struct READDIR3res READDIR3res; + +struct LINK3args { + nfs_fh3 file; + diropargs3 link; +}; +typedef struct LINK3args LINK3args; + +struct LINK3resok { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; +typedef struct LINK3resok LINK3resok; + +struct LINK3resfail { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; +typedef struct LINK3resfail LINK3resfail; + +struct LINK3res { + nfsstat3 status; + union { + LINK3resok resok; + LINK3resfail resfail; + }; +}; +typedef struct LINK3res LINK3res; + +struct sattrguard3 { + bool_t check; + union { + nfstime3 obj_ctime; + }; +}; +typedef struct sattrguard3 sattrguard3; + +struct SETATTR3args { + nfs_fh3 object; + sattr3 new_attributes; + sattrguard3 guard; +}; +typedef struct SETATTR3args SETATTR3args; + +struct SETATTR3resok { + wcc_data obj_wcc; +}; +typedef struct SETATTR3resok SETATTR3resok; + +struct SETATTR3resfail { + wcc_data obj_wcc; +}; +typedef struct SETATTR3resfail SETATTR3resfail; + +struct SETATTR3res { + nfsstat3 status; + union { + SETATTR3resok resok; + SETATTR3resfail resfail; + }; +}; +typedef struct SETATTR3res SETATTR3res; +#define FHSIZE2 32 + +typedef char fhandle2[FHSIZE2]; + +enum ftype2 { + NF2NON = 0, + NF2REG = 1, + NF2DIR = 2, + NF2BLK = 3, + NF2CHR = 4, + NF2LNK = 5, +}; +typedef enum ftype2 ftype2; + +struct fattr2 { + ftype2 type; + u_int mode; + u_int nlink; + u_int uid; + u_int gid; + u_int size; + u_int blocksize; + u_int rdev; + u_int blocks; + u_int fsid; + u_int fileid; + nfstime3 atime; + nfstime3 mtime; + nfstime3 ctime; +}; +typedef struct fattr2 fattr2; + +struct sattr2 { + u_int mode; + u_int uid; + u_int gid; + u_int size; + nfstime3 atime; + nfstime3 mtime; +}; +typedef struct sattr2 sattr2; +#define MAXNAMLEN2 255 + +typedef xdr_string_t filename2; +#define MAXPATHLEN2 1024 + +typedef xdr_string_t path2; +#define NFSMAXDATA2 8192 + +typedef xdr_string_t nfsdata2; +#define NFSCOOKIESIZE2 4 + +typedef char nfscookie2[NFSCOOKIESIZE2]; + +struct entry2 { + u_int fileid; + filename2 name; + nfscookie2 cookie; + struct entry2 *nextentry; +}; +typedef struct entry2 entry2; + +struct diropargs2 { + fhandle2 dir; + filename2 name; +}; +typedef struct diropargs2 diropargs2; + +struct GETATTR2args { + fhandle2 fhandle; +}; +typedef struct GETATTR2args GETATTR2args; + +struct GETATTR2resok { + fattr2 attributes; +}; +typedef struct GETATTR2resok GETATTR2resok; + +struct GETATTR2res { + nfsstat3 status; + union { + GETATTR2resok resok; + }; +}; +typedef struct GETATTR2res GETATTR2res; + +struct SETATTR2args { + fhandle2 fhandle; + sattr2 attributes; +}; +typedef struct SETATTR2args SETATTR2args; + +struct SETATTR2resok { + fattr2 attributes; +}; +typedef struct SETATTR2resok SETATTR2resok; + +struct SETATTR2res { + nfsstat3 status; + union { + SETATTR2resok resok; + }; +}; +typedef struct SETATTR2res SETATTR2res; + +struct LOOKUP2args { + diropargs2 what; +}; +typedef struct LOOKUP2args LOOKUP2args; + +struct LOOKUP2resok { + fhandle2 file; + fattr2 attributes; +}; +typedef struct LOOKUP2resok LOOKUP2resok; + +struct LOOKUP2res { + nfsstat3 status; + union { + LOOKUP2resok resok; + }; +}; +typedef struct LOOKUP2res LOOKUP2res; + +struct READLINK2args { + fhandle2 file; +}; +typedef struct READLINK2args READLINK2args; + +struct READLINK2resok { + path2 data; +}; +typedef struct READLINK2resok READLINK2resok; + +struct READLINK2res { + nfsstat3 status; + union { + READLINK2resok resok; + }; +}; +typedef struct READLINK2res READLINK2res; + +struct READ2args { + fhandle2 file; + u_int offset; + u_int count; + u_int totalcount; +}; +typedef struct READ2args READ2args; + +struct READ2resok { + fattr2 attributes; + nfsdata2 data; +}; +typedef struct READ2resok READ2resok; + +struct READ2res { + nfsstat3 status; + union { + READ2resok resok; + }; +}; +typedef struct READ2res READ2res; + +struct WRITE2args { + fhandle2 file; + u_int beginoffset; + u_int offset; + u_int totalcount; + nfsdata2 data; +}; +typedef struct WRITE2args WRITE2args; + +struct WRITE2resok { + fattr2 attributes; +}; +typedef struct WRITE2resok WRITE2resok; + +struct WRITE2res { + nfsstat3 status; + union { + WRITE2resok resok; + }; +}; +typedef struct WRITE2res WRITE2res; + +struct CREATE2args { + diropargs2 where; + sattr2 attributes; +}; +typedef struct CREATE2args CREATE2args; + +struct CREATE2resok { + fhandle2 file; + fattr2 attributes; +}; +typedef struct CREATE2resok CREATE2resok; + +struct CREATE2res { + nfsstat3 status; + union { + CREATE2resok resok; + }; +}; +typedef struct CREATE2res CREATE2res; + +struct REMOVE2args { + diropargs2 what; +}; +typedef struct REMOVE2args REMOVE2args; + +struct REMOVE2res { + nfsstat3 status; +}; +typedef struct REMOVE2res REMOVE2res; + +struct RENAME2args { + diropargs2 from; + diropargs2 to; +}; +typedef struct RENAME2args RENAME2args; + +struct RENAME2res { + nfsstat3 status; +}; +typedef struct RENAME2res RENAME2res; + +struct LINK2args { + fhandle2 from; + diropargs2 to; +}; +typedef struct LINK2args LINK2args; + +struct LINK2res { + nfsstat3 status; +}; +typedef struct LINK2res LINK2res; + +struct SYMLINK2args { + diropargs2 from; + path2 to; + sattr2 attributes; +}; +typedef struct SYMLINK2args SYMLINK2args; + +struct SYMLINK2res { + nfsstat3 status; +}; +typedef struct SYMLINK2res SYMLINK2res; + +struct MKDIR2args { + diropargs2 where; + sattr2 attributes; +}; +typedef struct MKDIR2args MKDIR2args; + +struct MKDIR2resok { + fhandle2 file; + fattr2 attributes; +}; +typedef struct MKDIR2resok MKDIR2resok; + +struct MKDIR2res { + nfsstat3 status; + union { + MKDIR2resok resok; + }; +}; +typedef struct MKDIR2res MKDIR2res; + +struct RMDIR2args { + diropargs2 what; +}; +typedef struct RMDIR2args RMDIR2args; + +struct RMDIR2res { + nfsstat3 status; +}; +typedef struct RMDIR2res RMDIR2res; + +struct READDIR2args { + fhandle2 dir; + nfscookie2 cookie; + u_int count; +}; +typedef struct READDIR2args READDIR2args; + +struct READDIR2resok { + entry2 *entries; + bool_t eof; +}; +typedef struct READDIR2resok READDIR2resok; + +struct READDIR2res { + nfsstat3 status; + union { + READDIR2resok resok; + }; +}; +typedef struct READDIR2res READDIR2res; + +struct STATFS2args { + fhandle2 dir; +}; +typedef struct STATFS2args STATFS2args; + +struct STATFS2resok { + u_int tsize; + u_int bsize; + u_int blocks; + u_int bfree; + u_int bavail; +}; +typedef struct STATFS2resok STATFS2resok; + +struct STATFS2res { + nfsstat3 status; + union { + STATFS2resok resok; + }; +}; +typedef struct STATFS2res STATFS2res; + +enum nfsacl_type { + NFSACL_TYPE_USER_OBJ = 0x0001, + NFSACL_TYPE_USER = 0x0002, + NFSACL_TYPE_GROUP_OBJ = 0x0004, + NFSACL_TYPE_GROUP = 0x0008, + NFSACL_TYPE_CLASS_OBJ = 0x0010, + NFSACL_TYPE_CLASS = 0x0020, + NFSACL_TYPE_DEFAULT = 0x1000, + NFSACL_TYPE_DEFAULT_USER_OBJ = 0x1001, + NFSACL_TYPE_DEFAULT_USER = 0x1002, + NFSACL_TYPE_DEFAULT_GROUP_OBJ = 0x1004, + NFSACL_TYPE_DEFAULT_GROUP = 0x1008, + NFSACL_TYPE_DEFAULT_CLASS_OBJ = 0x1010, + NFSACL_TYPE_DEFAULT_OTHER_OBJ = 0x1020, +}; +typedef enum nfsacl_type nfsacl_type; +#define NFSACL_PERM_READ 0x04 +#define NFSACL_PERM_WRITE 0x02 +#define NFSACL_PERM_EXEC 0x01 + +struct nfsacl_ace { + enum nfsacl_type type; + u_int id; + u_int perm; +}; +typedef struct nfsacl_ace nfsacl_ace; +#define NFSACL_MASK_ACL_ENTRY 0x0001 +#define NFSACL_MASK_ACL_COUNT 0x0002 +#define NFSACL_MASK_ACL_DEFAULT_ENTRY 0x0004 +#define NFSACL_MASK_ACL_DEFAULT_COUNT 0x0008 + +struct GETACL3args { + nfs_fh3 dir; + u_int mask; +}; +typedef struct GETACL3args GETACL3args; + +struct GETACL3resok { + post_op_attr attr; + u_int mask; + u_int ace_count; + struct { + u_int ace_len; + struct nfsacl_ace *ace_val; + } ace; + u_int default_ace_count; + struct { + u_int default_ace_len; + struct nfsacl_ace *default_ace_val; + } default_ace; +}; +typedef struct GETACL3resok GETACL3resok; + +struct GETACL3res { + nfsstat3 status; + union { + GETACL3resok resok; + }; +}; +typedef struct GETACL3res GETACL3res; + +struct SETACL3args { + nfs_fh3 dir; + u_int mask; + u_int ace_count; + struct { + u_int ace_len; + struct nfsacl_ace *ace_val; + } ace; + u_int default_ace_count; + struct { + u_int default_ace_len; + struct nfsacl_ace *default_ace_val; + } default_ace; +}; +typedef struct SETACL3args SETACL3args; + +struct SETACL3resok { + post_op_attr attr; +}; +typedef struct SETACL3resok SETACL3resok; + +struct SETACL3res { + nfsstat3 status; + union { + SETACL3resok resok; + }; +}; +typedef struct SETACL3res SETACL3res; +#define MNTPATHLEN 1024 +#define MNTNAMLEN 255 + +typedef xdr_string_t nfs_dirpath; + +typedef xdr_string_t nfs_name; + +enum nfs_mountstat3 { + MNT3_OK = 0, + MNT3ERR_PERM = 1, + MNT3ERR_NOENT = 2, + MNT3ERR_IO = 5, + MNT3ERR_ACCES = 13, + MNT3ERR_NOTDIR = 20, + MNT3ERR_INVAL = 22, + MNT3ERR_NAMETOOLONG = 63, + MNT3ERR_NOTSUPP = 10004, + MNT3ERR_SERVERFAULT = 10006, +}; +typedef enum nfs_mountstat3 nfs_mountstat3; + +typedef struct nfs_mountbody *nfs_mountlist; + +struct nfs_mountbody { + nfs_name ml_hostname; + nfs_dirpath ml_directory; + nfs_mountlist ml_next; +}; +typedef struct nfs_mountbody nfs_mountbody; + +typedef struct nfs_groupnode *nfs_groups; + +struct nfs_groupnode { + nfs_name gr_name; + nfs_groups gr_next; +}; +typedef struct nfs_groupnode nfs_groupnode; + +typedef struct nfs_exportnode *nfs_exports; + +struct nfs_exportnode { + nfs_dirpath ex_dir; + nfs_groups ex_groups; + nfs_exports ex_next; +}; +typedef struct nfs_exportnode nfs_exportnode; + +struct nfs_mountres3_ok { + nfs_fh3 fhandle; + struct { + u_int auth_flavors_len; + u_int *auth_flavors_val; + } auth_flavors; +}; +typedef struct nfs_mountres3_ok nfs_mountres3_ok; + +struct nfs_mountres3 { + nfs_mountstat3 fhs_status; + union { + nfs_mountres3_ok mountinfo; + }; +}; +typedef struct nfs_mountres3 nfs_mountres3; + +enum nfs_mountstat1 { + MNT1_OK = 0, + MNT1ERR_PERM = 1, + MNT1ERR_NOENT = 2, + MNT1ERR_IO = 5, + MNT1ERR_ACCES = 13, + MNT1ERR_NOTDIR = 20, + MNT1ERR_INVAL = 22, + MNT1ERR_NAMETOOLONG = 63, + MNT1ERR_NOTSUPP = 10004, + MNT1ERR_SERVERFAULT = 10006, +}; +typedef enum nfs_mountstat1 nfs_mountstat1; +#define FHSIZE 32 + +typedef char nfs_fhandle1[FHSIZE]; + +struct nfs_mountres1_ok { + nfs_fhandle1 fhandle; +}; +typedef struct nfs_mountres1_ok nfs_mountres1_ok; + +struct nfs_mountres1 { + nfs_mountstat1 fhs_status; + union { + nfs_mountres1_ok mountinfo; + }; +}; +typedef struct nfs_mountres1 nfs_mountres1; + +#define NFS_PROGRAM 100003 +#define NFS_V2 2 + + +#define NFS2_NULL 0 +#define NFS2_GETATTR 1 +#define NFS2_SETATTR 2 +#define NFS2_LOOKUP 4 +#define NFS2_READLINK 5 +#define NFS2_READ 6 +#define NFS2_WRITE 8 +#define NFS2_CREATE 9 +#define NFS2_REMOVE 10 +#define NFS2_RENAME 11 +#define NFS2_LINK 12 +#define NFS2_SYMLINK 13 +#define NFS2_MKDIR 14 +#define NFS2_RMDIR 15 +#define NFS2_READDIR 16 +#define NFS2_STATFS 17 + +#define NFS_V3 3 + + +#define NFS3_NULL 0 +#define NFS3_GETATTR 1 +#define NFS3_SETATTR 2 +#define NFS3_LOOKUP 3 +#define NFS3_ACCESS 4 +#define NFS3_READLINK 5 +#define NFS3_READ 6 +#define NFS3_WRITE 7 +#define NFS3_CREATE 8 +#define NFS3_MKDIR 9 +#define NFS3_SYMLINK 10 +#define NFS3_MKNOD 11 +#define NFS3_REMOVE 12 +#define NFS3_RMDIR 13 +#define NFS3_RENAME 14 +#define NFS3_LINK 15 +#define NFS3_READDIR 16 +#define NFS3_READDIRPLUS 17 +#define NFS3_FSSTAT 18 +#define NFS3_FSINFO 19 +#define NFS3_PATHCONF 20 +#define NFS3_COMMIT 21 + + +#define NFSACL_PROGRAM 100227 +#define NFSACL_V3 3 + + +#define NFSACL3_NULL 0 +#define NFSACL3_GETACL 1 +#define NFSACL3_SETACL 2 + + +#define MOUNT_PROGRAM 100005 +#define MOUNT_V1 1 + + +#define MOUNT1_NULL 0 +#define MOUNT1_MNT 1 +#define MOUNT1_DUMP 2 +#define MOUNT1_UMNT 3 +#define MOUNT1_UMNTALL 4 +#define MOUNT1_EXPORT 5 + +#define MOUNT_V3 3 + + +#define MOUNT3_NULL 0 +#define MOUNT3_MNT 1 +#define MOUNT3_DUMP 2 +#define MOUNT3_UMNT 3 +#define MOUNT3_UMNTALL 4 +#define MOUNT3_EXPORT 5 + + +/* the xdr functions */ + + +extern bool_t xdr_cookieverf3 (XDR *, cookieverf3); +extern bool_t xdr_cookie3 (XDR *, cookie3*); +extern bool_t xdr_nfs_fh3 (XDR *, nfs_fh3*); +extern bool_t xdr_filename3 (XDR *, filename3*); +extern bool_t xdr_diropargs3 (XDR *, diropargs3*); +extern bool_t xdr_ftype3 (XDR *, ftype3*); +extern bool_t xdr_mode3 (XDR *, mode3*); +extern bool_t xdr_uid3 (XDR *, uid3*); +extern bool_t xdr_gid3 (XDR *, gid3*); +extern bool_t xdr_size3 (XDR *, size3*); +extern bool_t xdr_fileid3 (XDR *, fileid3*); +extern bool_t xdr_specdata3 (XDR *, specdata3*); +extern bool_t xdr_nfstime3 (XDR *, nfstime3*); +extern bool_t xdr_fattr3 (XDR *, fattr3*); +extern bool_t xdr_post_op_attr (XDR *, post_op_attr*); +extern bool_t xdr_nfsstat3 (XDR *, nfsstat3*); +extern bool_t xdr_stable_how (XDR *, stable_how*); +extern bool_t xdr_offset3 (XDR *, offset3*); +extern bool_t xdr_count3 (XDR *, count3*); +extern bool_t xdr_wcc_attr (XDR *, wcc_attr*); +extern bool_t xdr_pre_op_attr (XDR *, pre_op_attr*); +extern bool_t xdr_wcc_data (XDR *, wcc_data*); +extern bool_t xdr_WRITE3args (XDR *, WRITE3args*); +extern bool_t xdr_writeverf3 (XDR *, writeverf3); +extern bool_t xdr_WRITE3resok (XDR *, WRITE3resok*); +extern bool_t xdr_WRITE3resfail (XDR *, WRITE3resfail*); +extern bool_t xdr_WRITE3res (XDR *, WRITE3res*); +extern bool_t xdr_LOOKUP3args (XDR *, LOOKUP3args*); +extern bool_t xdr_LOOKUP3resok (XDR *, LOOKUP3resok*); +extern bool_t xdr_LOOKUP3resfail (XDR *, LOOKUP3resfail*); +extern bool_t xdr_LOOKUP3res (XDR *, LOOKUP3res*); +extern bool_t xdr_COMMIT3args (XDR *, COMMIT3args*); +extern bool_t xdr_COMMIT3resok (XDR *, COMMIT3resok*); +extern bool_t xdr_COMMIT3resfail (XDR *, COMMIT3resfail*); +extern bool_t xdr_COMMIT3res (XDR *, COMMIT3res*); +extern bool_t xdr_ACCESS3args (XDR *, ACCESS3args*); +extern bool_t xdr_ACCESS3resok (XDR *, ACCESS3resok*); +extern bool_t xdr_ACCESS3resfail (XDR *, ACCESS3resfail*); +extern bool_t xdr_ACCESS3res (XDR *, ACCESS3res*); +extern bool_t xdr_GETATTR3args (XDR *, GETATTR3args*); +extern bool_t xdr_GETATTR3resok (XDR *, GETATTR3resok*); +extern bool_t xdr_GETATTR3res (XDR *, GETATTR3res*); +extern bool_t xdr_time_how (XDR *, time_how*); +extern bool_t xdr_set_mode3 (XDR *, set_mode3*); +extern bool_t xdr_set_uid3 (XDR *, set_uid3*); +extern bool_t xdr_set_gid3 (XDR *, set_gid3*); +extern bool_t xdr_set_size3 (XDR *, set_size3*); +extern bool_t xdr_set_atime (XDR *, set_atime*); +extern bool_t xdr_set_mtime (XDR *, set_mtime*); +extern bool_t xdr_sattr3 (XDR *, sattr3*); +extern bool_t xdr_createmode3 (XDR *, createmode3*); +extern bool_t xdr_createverf3 (XDR *, createverf3); +extern bool_t xdr_createhow3 (XDR *, createhow3*); +extern bool_t xdr_CREATE3args (XDR *, CREATE3args*); +extern bool_t xdr_post_op_fh3 (XDR *, post_op_fh3*); +extern bool_t xdr_CREATE3resok (XDR *, CREATE3resok*); +extern bool_t xdr_CREATE3resfail (XDR *, CREATE3resfail*); +extern bool_t xdr_CREATE3res (XDR *, CREATE3res*); +extern bool_t xdr_REMOVE3args (XDR *, REMOVE3args*); +extern bool_t xdr_REMOVE3resok (XDR *, REMOVE3resok*); +extern bool_t xdr_REMOVE3resfail (XDR *, REMOVE3resfail*); +extern bool_t xdr_REMOVE3res (XDR *, REMOVE3res*); +extern bool_t xdr_READ3args (XDR *, READ3args*); +extern bool_t xdr_READ3resok (XDR *, READ3resok*); +extern bool_t xdr_READ3resfail (XDR *, READ3resfail*); +extern bool_t xdr_READ3res (XDR *, READ3res*); +extern bool_t xdr_FSINFO3args (XDR *, FSINFO3args*); +extern bool_t xdr_FSINFO3resok (XDR *, FSINFO3resok*); +extern bool_t xdr_FSINFO3resfail (XDR *, FSINFO3resfail*); +extern bool_t xdr_FSINFO3res (XDR *, FSINFO3res*); +extern bool_t xdr_FSSTAT3args (XDR *, FSSTAT3args*); +extern bool_t xdr_FSSTAT3resok (XDR *, FSSTAT3resok*); +extern bool_t xdr_FSSTAT3resfail (XDR *, FSSTAT3resfail*); +extern bool_t xdr_FSSTAT3res (XDR *, FSSTAT3res*); +extern bool_t xdr_PATHCONF3args (XDR *, PATHCONF3args*); +extern bool_t xdr_PATHCONF3resok (XDR *, PATHCONF3resok*); +extern bool_t xdr_PATHCONF3resfail (XDR *, PATHCONF3resfail*); +extern bool_t xdr_PATHCONF3res (XDR *, PATHCONF3res*); +extern bool_t xdr_nfspath3 (XDR *, nfspath3*); +extern bool_t xdr_symlinkdata3 (XDR *, symlinkdata3*); +extern bool_t xdr_SYMLINK3args (XDR *, SYMLINK3args*); +extern bool_t xdr_SYMLINK3resok (XDR *, SYMLINK3resok*); +extern bool_t xdr_SYMLINK3resfail (XDR *, SYMLINK3resfail*); +extern bool_t xdr_SYMLINK3res (XDR *, SYMLINK3res*); +extern bool_t xdr_READLINK3args (XDR *, READLINK3args*); +extern bool_t xdr_READLINK3resok (XDR *, READLINK3resok*); +extern bool_t xdr_READLINK3resfail (XDR *, READLINK3resfail*); +extern bool_t xdr_READLINK3res (XDR *, READLINK3res*); +extern bool_t xdr_devicedata3 (XDR *, devicedata3*); +extern bool_t xdr_mknoddata3 (XDR *, mknoddata3*); +extern bool_t xdr_MKNOD3args (XDR *, MKNOD3args*); +extern bool_t xdr_MKNOD3resok (XDR *, MKNOD3resok*); +extern bool_t xdr_MKNOD3resfail (XDR *, MKNOD3resfail*); +extern bool_t xdr_MKNOD3res (XDR *, MKNOD3res*); +extern bool_t xdr_MKDIR3args (XDR *, MKDIR3args*); +extern bool_t xdr_MKDIR3resok (XDR *, MKDIR3resok*); +extern bool_t xdr_MKDIR3resfail (XDR *, MKDIR3resfail*); +extern bool_t xdr_MKDIR3res (XDR *, MKDIR3res*); +extern bool_t xdr_RMDIR3args (XDR *, RMDIR3args*); +extern bool_t xdr_RMDIR3resok (XDR *, RMDIR3resok*); +extern bool_t xdr_RMDIR3resfail (XDR *, RMDIR3resfail*); +extern bool_t xdr_RMDIR3res (XDR *, RMDIR3res*); +extern bool_t xdr_RENAME3args (XDR *, RENAME3args*); +extern bool_t xdr_RENAME3resok (XDR *, RENAME3resok*); +extern bool_t xdr_RENAME3resfail (XDR *, RENAME3resfail*); +extern bool_t xdr_RENAME3res (XDR *, RENAME3res*); +extern bool_t xdr_READDIRPLUS3args (XDR *, READDIRPLUS3args*); +extern bool_t xdr_entryplus3 (XDR *, entryplus3*); +extern bool_t xdr_dirlistplus3 (XDR *, dirlistplus3*); +extern bool_t xdr_READDIRPLUS3resok (XDR *, READDIRPLUS3resok*); +extern bool_t xdr_READDIRPLUS3resfail (XDR *, READDIRPLUS3resfail*); +extern bool_t xdr_READDIRPLUS3res (XDR *, READDIRPLUS3res*); +extern bool_t xdr_READDIR3args (XDR *, READDIR3args*); +extern bool_t xdr_entry3 (XDR *, entry3*); +extern bool_t xdr_dirlist3 (XDR *, dirlist3*); +extern bool_t xdr_READDIR3resok (XDR *, READDIR3resok*); +extern bool_t xdr_READDIR3resfail (XDR *, READDIR3resfail*); +extern bool_t xdr_READDIR3res (XDR *, READDIR3res*); +extern bool_t xdr_LINK3args (XDR *, LINK3args*); +extern bool_t xdr_LINK3resok (XDR *, LINK3resok*); +extern bool_t xdr_LINK3resfail (XDR *, LINK3resfail*); +extern bool_t xdr_LINK3res (XDR *, LINK3res*); +extern bool_t xdr_sattrguard3 (XDR *, sattrguard3*); +extern bool_t xdr_SETATTR3args (XDR *, SETATTR3args*); +extern bool_t xdr_SETATTR3resok (XDR *, SETATTR3resok*); +extern bool_t xdr_SETATTR3resfail (XDR *, SETATTR3resfail*); +extern bool_t xdr_SETATTR3res (XDR *, SETATTR3res*); +extern bool_t xdr_fhandle2 (XDR *, fhandle2); +extern bool_t xdr_ftype2 (XDR *, ftype2*); +extern bool_t xdr_fattr2 (XDR *, fattr2*); +extern bool_t xdr_sattr2 (XDR *, sattr2*); +extern bool_t xdr_filename2 (XDR *, filename2*); +extern bool_t xdr_path2 (XDR *, path2*); +extern bool_t xdr_nfsdata2 (XDR *, nfsdata2*); +extern bool_t xdr_nfscookie2 (XDR *, nfscookie2); +extern bool_t xdr_entry2 (XDR *, entry2*); +extern bool_t xdr_diropargs2 (XDR *, diropargs2*); +extern bool_t xdr_GETATTR2args (XDR *, GETATTR2args*); +extern bool_t xdr_GETATTR2resok (XDR *, GETATTR2resok*); +extern bool_t xdr_GETATTR2res (XDR *, GETATTR2res*); +extern bool_t xdr_SETATTR2args (XDR *, SETATTR2args*); +extern bool_t xdr_SETATTR2resok (XDR *, SETATTR2resok*); +extern bool_t xdr_SETATTR2res (XDR *, SETATTR2res*); +extern bool_t xdr_LOOKUP2args (XDR *, LOOKUP2args*); +extern bool_t xdr_LOOKUP2resok (XDR *, LOOKUP2resok*); +extern bool_t xdr_LOOKUP2res (XDR *, LOOKUP2res*); +extern bool_t xdr_READLINK2args (XDR *, READLINK2args*); +extern bool_t xdr_READLINK2resok (XDR *, READLINK2resok*); +extern bool_t xdr_READLINK2res (XDR *, READLINK2res*); +extern bool_t xdr_READ2args (XDR *, READ2args*); +extern bool_t xdr_READ2resok (XDR *, READ2resok*); +extern bool_t xdr_READ2res (XDR *, READ2res*); +extern bool_t xdr_WRITE2args (XDR *, WRITE2args*); +extern bool_t xdr_WRITE2resok (XDR *, WRITE2resok*); +extern bool_t xdr_WRITE2res (XDR *, WRITE2res*); +extern bool_t xdr_CREATE2args (XDR *, CREATE2args*); +extern bool_t xdr_CREATE2resok (XDR *, CREATE2resok*); +extern bool_t xdr_CREATE2res (XDR *, CREATE2res*); +extern bool_t xdr_REMOVE2args (XDR *, REMOVE2args*); +extern bool_t xdr_REMOVE2res (XDR *, REMOVE2res*); +extern bool_t xdr_RENAME2args (XDR *, RENAME2args*); +extern bool_t xdr_RENAME2res (XDR *, RENAME2res*); +extern bool_t xdr_LINK2args (XDR *, LINK2args*); +extern bool_t xdr_LINK2res (XDR *, LINK2res*); +extern bool_t xdr_SYMLINK2args (XDR *, SYMLINK2args*); +extern bool_t xdr_SYMLINK2res (XDR *, SYMLINK2res*); +extern bool_t xdr_MKDIR2args (XDR *, MKDIR2args*); +extern bool_t xdr_MKDIR2resok (XDR *, MKDIR2resok*); +extern bool_t xdr_MKDIR2res (XDR *, MKDIR2res*); +extern bool_t xdr_RMDIR2args (XDR *, RMDIR2args*); +extern bool_t xdr_RMDIR2res (XDR *, RMDIR2res*); +extern bool_t xdr_READDIR2args (XDR *, READDIR2args*); +extern bool_t xdr_READDIR2resok (XDR *, READDIR2resok*); +extern bool_t xdr_READDIR2res (XDR *, READDIR2res*); +extern bool_t xdr_STATFS2args (XDR *, STATFS2args*); +extern bool_t xdr_STATFS2resok (XDR *, STATFS2resok*); +extern bool_t xdr_STATFS2res (XDR *, STATFS2res*); +extern bool_t xdr_nfsacl_type (XDR *, nfsacl_type*); +extern bool_t xdr_nfsacl_ace (XDR *, nfsacl_ace*); +extern bool_t xdr_GETACL3args (XDR *, GETACL3args*); +extern bool_t xdr_GETACL3resok (XDR *, GETACL3resok*); +extern bool_t xdr_GETACL3res (XDR *, GETACL3res*); +extern bool_t xdr_SETACL3args (XDR *, SETACL3args*); +extern bool_t xdr_SETACL3resok (XDR *, SETACL3resok*); +extern bool_t xdr_SETACL3res (XDR *, SETACL3res*); +extern bool_t xdr_nfs_dirpath (XDR *, nfs_dirpath*); +extern bool_t xdr_nfs_name (XDR *, nfs_name*); +extern bool_t xdr_nfs_mountstat3 (XDR *, nfs_mountstat3*); +extern bool_t xdr_nfs_mountlist (XDR *, nfs_mountlist*); +extern bool_t xdr_nfs_mountbody (XDR *, nfs_mountbody*); +extern bool_t xdr_nfs_groups (XDR *, nfs_groups*); +extern bool_t xdr_nfs_groupnode (XDR *, nfs_groupnode*); +extern bool_t xdr_nfs_exports (XDR *, nfs_exports*); +extern bool_t xdr_nfs_exportnode (XDR *, nfs_exportnode*); +extern bool_t xdr_nfs_mountres3_ok (XDR *, nfs_mountres3_ok*); +extern bool_t xdr_nfs_mountres3 (XDR *, nfs_mountres3*); +extern bool_t xdr_nfs_mountstat1 (XDR *, nfs_mountstat1*); +extern bool_t xdr_nfs_fhandle1 (XDR *, nfs_fhandle1); +extern bool_t xdr_nfs_mountres1_ok (XDR *, nfs_mountres1_ok*); +extern bool_t xdr_nfs_mountres1 (XDR *, nfs_mountres1*); + + +#ifdef __cplusplus +} +#endif + +#endif /* !_NFS_H_RPCGEN */ diff --git a/src/nfs/nfs.x b/src/nfs/nfs.x new file mode 100644 index 000000000..738516a07 --- /dev/null +++ b/src/nfs/nfs.x @@ -0,0 +1,1380 @@ +/* Based on RFC 1813 - NFS Version 3 Protocol Specification */ + +/* +Copyright (c) 2014, Ronnie Sahlberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +/* + * NFS v3 Definitions + */ +const NFS3_FHSIZE = 64; /* Maximum bytes in a V3 file handle */ +const NFS3_WRITEVERFSIZE = 8; +const NFS3_CREATEVERFSIZE = 8; +const NFS3_COOKIEVERFSIZE = 8; + +typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; + +typedef uint64_t cookie3; + +typedef opaque nfs_fh3; + +typedef string filename3<>; + +struct diropargs3 { + nfs_fh3 dir; + filename3 name; +}; + +enum ftype3 { + NF3REG = 1, + NF3DIR = 2, + NF3BLK = 3, + NF3CHR = 4, + NF3LNK = 5, + NF3SOCK = 6, + NF3FIFO = 7 +}; + +typedef unsigned int mode3; + +typedef unsigned int uid3; + +typedef unsigned int gid3; + +typedef uint64_t size3; + +typedef uint64_t fileid3; + +struct specdata3 { + unsigned int specdata1; + unsigned int specdata2; +}; + +struct nfstime3 { + unsigned int seconds; + unsigned int nseconds; +}; + +struct fattr3 { + ftype3 type; + mode3 mode; + unsigned int nlink; + uid3 uid; + gid3 gid; + size3 size; + size3 used; + specdata3 rdev; + uint64_t fsid; + fileid3 fileid; + nfstime3 atime; + nfstime3 mtime; + nfstime3 ctime; +}; + +union post_op_attr switch (bool attributes_follow) { + case TRUE: + fattr3 attributes; + case FALSE: + void; +}; + +enum nfsstat3 { + NFS3_OK = 0, + NFS3ERR_PERM = 1, + NFS3ERR_NOENT = 2, + NFS3ERR_IO = 5, + NFS3ERR_NXIO = 6, + NFS3ERR_ACCES = 13, + NFS3ERR_EXIST = 17, + NFS3ERR_XDEV = 18, + NFS3ERR_NODEV = 19, + NFS3ERR_NOTDIR = 20, + NFS3ERR_ISDIR = 21, + NFS3ERR_INVAL = 22, + NFS3ERR_FBIG = 27, + NFS3ERR_NOSPC = 28, + NFS3ERR_ROFS = 30, + NFS3ERR_MLINK = 31, + NFS3ERR_NAMETOOLONG = 63, + NFS3ERR_NOTEMPTY = 66, + NFS3ERR_DQUOT = 69, + NFS3ERR_STALE = 70, + NFS3ERR_REMOTE = 71, + NFS3ERR_BADHANDLE = 10001, + NFS3ERR_NOT_SYNC = 10002, + NFS3ERR_BAD_COOKIE = 10003, + NFS3ERR_NOTSUPP = 10004, + NFS3ERR_TOOSMALL = 10005, + NFS3ERR_SERVERFAULT = 10006, + NFS3ERR_BADTYPE = 10007, + NFS3ERR_JUKEBOX = 10008 +}; + +enum stable_how { + UNSTABLE = 0, + DATA_SYNC = 1, + FILE_SYNC = 2 +}; + +typedef uint64_t offset3; + +typedef unsigned int count3; + +struct wcc_attr { + size3 size; + nfstime3 mtime; + nfstime3 ctime; +}; + +union pre_op_attr switch (bool attributes_follow) { + case TRUE: + wcc_attr attributes; + case FALSE: + void; +}; + +struct wcc_data { + pre_op_attr before; + post_op_attr after; +}; + +struct WRITE3args { + nfs_fh3 file; + offset3 offset; + count3 count; + stable_how stable; + opaque data<>; +}; + +typedef opaque writeverf3[NFS3_WRITEVERFSIZE]; + +struct WRITE3resok { + wcc_data file_wcc; + count3 count; + stable_how committed; + writeverf3 verf; +}; + +struct WRITE3resfail { + wcc_data file_wcc; +}; + +union WRITE3res switch (nfsstat3 status) { + case NFS3_OK: + WRITE3resok resok; + default: + WRITE3resfail resfail; +}; + +struct LOOKUP3args { + diropargs3 what; +}; + +struct LOOKUP3resok { + nfs_fh3 object; + post_op_attr obj_attributes; + post_op_attr dir_attributes; +}; + +struct LOOKUP3resfail { + post_op_attr dir_attributes; +}; + +union LOOKUP3res switch (nfsstat3 status) { + case NFS3_OK: + LOOKUP3resok resok; + default: + LOOKUP3resfail resfail; +}; + +struct COMMIT3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; + +struct COMMIT3resok { + wcc_data file_wcc; + writeverf3 verf; +}; + +struct COMMIT3resfail { + wcc_data file_wcc; +}; + +union COMMIT3res switch (nfsstat3 status) { + case NFS3_OK: + COMMIT3resok resok; + default: + COMMIT3resfail resfail; +}; + +const ACCESS3_READ = 0x0001; +const ACCESS3_LOOKUP = 0x0002; +const ACCESS3_MODIFY = 0x0004; +const ACCESS3_EXTEND = 0x0008; +const ACCESS3_DELETE = 0x0010; +const ACCESS3_EXECUTE = 0x0020; + +struct ACCESS3args { + nfs_fh3 object; + unsigned int access; +}; + +struct ACCESS3resok { + post_op_attr obj_attributes; + unsigned int access; +}; + +struct ACCESS3resfail { + post_op_attr obj_attributes; +}; + +union ACCESS3res switch (nfsstat3 status) { +case NFS3_OK: + ACCESS3resok resok; +default: + ACCESS3resfail resfail; +}; + +struct GETATTR3args { + nfs_fh3 object; +}; + +struct GETATTR3resok { + fattr3 obj_attributes; +}; + +union GETATTR3res switch (nfsstat3 status) { + case NFS3_OK: + GETATTR3resok resok; + default: + void; +}; + +enum time_how { + DONT_CHANGE = 0, + SET_TO_SERVER_TIME = 1, + SET_TO_CLIENT_TIME = 2 +}; + +union set_mode3 switch (bool set_it) { + case TRUE: + mode3 mode; + default: + void; +}; + +union set_uid3 switch (bool set_it) { + case TRUE: + uid3 uid; + default: + void; +}; + +union set_gid3 switch (bool set_it) { + case TRUE: + gid3 gid; + default: + void; +}; + +union set_size3 switch (bool set_it) { + case TRUE: + size3 size; + default: + void; +}; + +union set_atime switch (time_how set_it) { + case SET_TO_CLIENT_TIME: + nfstime3 atime; + default: + void; +}; + +union set_mtime switch (time_how set_it) { + case SET_TO_CLIENT_TIME: + nfstime3 mtime; + default: + void; +}; + +struct sattr3 { + set_mode3 mode; + set_uid3 uid; + set_gid3 gid; + set_size3 size; + set_atime atime; + set_mtime mtime; +}; + +enum createmode3 { + NFS_UNCHECKED = 0, + NFS_GUARDED = 1, + NFS_EXCLUSIVE = 2 +}; + +typedef opaque createverf3[NFS3_CREATEVERFSIZE]; + +union createhow3 switch (createmode3 mode) { + case NFS_UNCHECKED: + sattr3 obj_attributes; + case NFS_GUARDED: + sattr3 g_obj_attributes; + case NFS_EXCLUSIVE: + createverf3 verf; +}; + +struct CREATE3args { + diropargs3 where; + createhow3 how; +}; + +union post_op_fh3 switch (bool handle_follows) { + case TRUE: + nfs_fh3 handle; + case FALSE: + void; +}; + +struct CREATE3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct CREATE3resfail { + wcc_data dir_wcc; + }; + +union CREATE3res switch (nfsstat3 status) { + case NFS3_OK: + CREATE3resok resok; + default: + CREATE3resfail resfail; +}; + +struct REMOVE3args { + diropargs3 object; +}; + +struct REMOVE3resok { + wcc_data dir_wcc; +}; + +struct REMOVE3resfail { + wcc_data dir_wcc; +}; + +union REMOVE3res switch (nfsstat3 status) { + case NFS3_OK: + REMOVE3resok resok; + default: + REMOVE3resfail resfail; +}; + +struct READ3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; + +struct READ3resok { + post_op_attr file_attributes; + count3 count; + bool eof; + opaque data<>; +}; + +struct READ3resfail { + post_op_attr file_attributes; +}; + +union READ3res switch (nfsstat3 status) { + case NFS3_OK: + READ3resok resok; + default: + READ3resfail resfail; +}; + + +const FSF3_LINK = 0x0001; +const FSF3_SYMLINK = 0x0002; +const FSF3_HOMOGENEOUS = 0x0008; +const FSF3_CANSETTIME = 0x0010; + +struct FSINFO3args { + nfs_fh3 fsroot; +}; + +struct FSINFO3resok { + post_op_attr obj_attributes; + unsigned int rtmax; + unsigned int rtpref; + unsigned int rtmult; + unsigned int wtmax; + unsigned int wtpref; + unsigned int wtmult; + unsigned int dtpref; + size3 maxfilesize; + nfstime3 time_delta; + unsigned int properties; +}; + +struct FSINFO3resfail { + post_op_attr obj_attributes; +}; + +union FSINFO3res switch (nfsstat3 status) { + case NFS3_OK: + FSINFO3resok resok; + default: + FSINFO3resfail resfail; +}; + + +struct FSSTAT3args { + nfs_fh3 fsroot; +}; + +struct FSSTAT3resok { + post_op_attr obj_attributes; + size3 tbytes; + size3 fbytes; + size3 abytes; + size3 tfiles; + size3 ffiles; + size3 afiles; + unsigned int invarsec; +}; + +struct FSSTAT3resfail { + post_op_attr obj_attributes; +}; + +union FSSTAT3res switch (nfsstat3 status) { + case NFS3_OK: + FSSTAT3resok resok; + default: + FSSTAT3resfail resfail; +}; + +struct PATHCONF3args { + nfs_fh3 object; +}; + +struct PATHCONF3resok { + post_op_attr obj_attributes; + unsigned int linkmax; + unsigned int name_max; + bool no_trunc; + bool chown_restricted; + bool case_insensitive; + bool case_preserving; +}; + +struct PATHCONF3resfail { + post_op_attr obj_attributes; +}; + +union PATHCONF3res switch (nfsstat3 status) { + case NFS3_OK: + PATHCONF3resok resok; + default: + PATHCONF3resfail resfail; +}; + +typedef string nfspath3<>; + +struct symlinkdata3 { + sattr3 symlink_attributes; + nfspath3 symlink_data; +}; + +struct SYMLINK3args { + diropargs3 where; + symlinkdata3 symlink; +}; + +struct SYMLINK3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct SYMLINK3resfail { + wcc_data dir_wcc; +}; + +union SYMLINK3res switch (nfsstat3 status) { + case NFS3_OK: + SYMLINK3resok resok; + default: + SYMLINK3resfail resfail; +}; + + +struct READLINK3args { + nfs_fh3 symlink; +}; + +struct READLINK3resok { + post_op_attr symlink_attributes; + nfspath3 data; +}; + +struct READLINK3resfail { + post_op_attr symlink_attributes; +}; + +union READLINK3res switch (nfsstat3 status) { + case NFS3_OK: + READLINK3resok resok; + default: + READLINK3resfail resfail; +}; + +struct devicedata3 { + sattr3 dev_attributes; + specdata3 spec; +}; + +union mknoddata3 switch (ftype3 type) { + case NF3CHR: + devicedata3 chr_device; + case NF3BLK: + devicedata3 blk_device; + case NF3SOCK: + sattr3 sock_attributes; + case NF3FIFO: + sattr3 pipe_attributes; + default: + void; +}; + +struct MKNOD3args { + diropargs3 where; + mknoddata3 what; +}; + +struct MKNOD3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct MKNOD3resfail { + wcc_data dir_wcc; +}; + +union MKNOD3res switch (nfsstat3 status) { + case NFS3_OK: + MKNOD3resok resok; + default: + MKNOD3resfail resfail; +}; + +struct MKDIR3args { + diropargs3 where; + sattr3 attributes; +}; + +struct MKDIR3resok { + post_op_fh3 obj; + post_op_attr obj_attributes; + wcc_data dir_wcc; +}; + +struct MKDIR3resfail { + wcc_data dir_wcc; +}; + +union MKDIR3res switch (nfsstat3 status) { + case NFS3_OK: + MKDIR3resok resok; + default: + MKDIR3resfail resfail; +}; + +struct RMDIR3args { + diropargs3 object; +}; + +struct RMDIR3resok { + wcc_data dir_wcc; +}; + +struct RMDIR3resfail { + wcc_data dir_wcc; +}; + +union RMDIR3res switch (nfsstat3 status) { + case NFS3_OK: + RMDIR3resok resok; + default: + RMDIR3resfail resfail; +}; + +struct RENAME3args { + diropargs3 from; + diropargs3 to; +}; + +struct RENAME3resok { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; + +struct RENAME3resfail { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; + +union RENAME3res switch (nfsstat3 status) { + case NFS3_OK: + RENAME3resok resok; + default: + RENAME3resfail resfail; +}; + +struct READDIRPLUS3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 dircount; + count3 maxcount; +}; + +struct entryplus3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + post_op_attr name_attributes; + post_op_fh3 name_handle; + entryplus3 *nextentry; +}; + +struct dirlistplus3 { + entryplus3 *entries; + bool eof; +}; + +struct READDIRPLUS3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlistplus3 reply; +}; + +struct READDIRPLUS3resfail { + post_op_attr dir_attributes; +}; + +union READDIRPLUS3res switch (nfsstat3 status) { + case NFS3_OK: + READDIRPLUS3resok resok; + default: + READDIRPLUS3resfail resfail; +}; + +struct READDIR3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 count; +}; + +struct entry3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + entry3 *nextentry; +}; + +struct dirlist3 { + entry3 *entries; + bool eof; +}; + +struct READDIR3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlist3 reply; +}; + +struct READDIR3resfail { + post_op_attr dir_attributes; +}; + +union READDIR3res switch (nfsstat3 status) { + case NFS3_OK: + READDIR3resok resok; + default: + READDIR3resfail resfail; +}; + +struct LINK3args { + nfs_fh3 file; + diropargs3 link; +}; + +struct LINK3resok { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; + +struct LINK3resfail { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; + +union LINK3res switch (nfsstat3 status) { + case NFS3_OK: + LINK3resok resok; + default: + LINK3resfail resfail; +}; + +union sattrguard3 switch (bool check) { + case TRUE: + nfstime3 obj_ctime; + case FALSE: + void; +}; + +struct SETATTR3args { + nfs_fh3 object; + sattr3 new_attributes; + sattrguard3 guard; +}; + +struct SETATTR3resok { + wcc_data obj_wcc; +}; + +struct SETATTR3resfail { + wcc_data obj_wcc; +}; + +union SETATTR3res switch (nfsstat3 status) { + case NFS3_OK: + SETATTR3resok resok; + default: + SETATTR3resfail resfail; +}; + +/* + * NFS v2 Definitions + * We share many definitions from v3 + */ +const FHSIZE2 = 32; +typedef opaque fhandle2[FHSIZE2]; + +enum ftype2 { + NF2NON = 0, + NF2REG = 1, + NF2DIR = 2, + NF2BLK = 3, + NF2CHR = 4, + NF2LNK = 5 +}; + +struct fattr2 { + ftype2 type; + unsigned int mode; + unsigned int nlink; + unsigned int uid; + unsigned int gid; + unsigned int size; + unsigned int blocksize; + unsigned int rdev; + unsigned int blocks; + unsigned int fsid; + unsigned int fileid; + nfstime3 atime; + nfstime3 mtime; + nfstime3 ctime; +}; + +struct sattr2 { + unsigned int mode; + unsigned int uid; + unsigned int gid; + unsigned int size; + nfstime3 atime; + nfstime3 mtime; +}; + +const MAXNAMLEN2 = 255; +typedef string filename2; + +const MAXPATHLEN2 = 1024; +typedef string path2; + +const NFSMAXDATA2 = 8192; +typedef opaque nfsdata2; + +const NFSCOOKIESIZE2 = 4; +typedef opaque nfscookie2[NFSCOOKIESIZE2]; + +struct entry2 { + unsigned int fileid; + filename2 name; + nfscookie2 cookie; + entry2 *nextentry; +}; + +struct diropargs2 { + fhandle2 dir; + filename2 name; +}; + +struct GETATTR2args { + fhandle2 fhandle; +}; + +struct GETATTR2resok { + fattr2 attributes; +}; + +union GETATTR2res switch (nfsstat3 status) { + case NFS3_OK: + GETATTR2resok resok; + default: + void; +}; + +struct SETATTR2args { + fhandle2 fhandle; + sattr2 attributes; +}; + +struct SETATTR2resok { + fattr2 attributes; +}; + +union SETATTR2res switch (nfsstat3 status) { + case NFS3_OK: + SETATTR2resok resok; + default: + void; +}; + +struct LOOKUP2args { + diropargs2 what; +}; + +struct LOOKUP2resok { + fhandle2 file; + fattr2 attributes; +}; + +union LOOKUP2res switch (nfsstat3 status) { + case NFS3_OK: + LOOKUP2resok resok; + default: + void; +}; + +struct READLINK2args { + fhandle2 file; +}; + +struct READLINK2resok { + path2 data; +}; + +union READLINK2res switch (nfsstat3 status) { + case NFS3_OK: + READLINK2resok resok; + default: + void; +}; + +struct READ2args { + fhandle2 file; + unsigned int offset; + unsigned int count; + unsigned int totalcount; +}; + +struct READ2resok { + fattr2 attributes; + nfsdata2 data; +}; + +union READ2res switch (nfsstat3 status) { + case NFS3_OK: + READ2resok resok; + default: + void; +}; + +struct WRITE2args { + fhandle2 file; + unsigned int beginoffset; + unsigned int offset; + unsigned int totalcount; + nfsdata2 data; +}; + +struct WRITE2resok { + fattr2 attributes; +}; + +union WRITE2res switch (nfsstat3 status) { + case NFS3_OK: + WRITE2resok resok; + default: + void; +}; + +struct CREATE2args { + diropargs2 where; + sattr2 attributes; +}; + +struct CREATE2resok { + fhandle2 file; + fattr2 attributes; +}; + +union CREATE2res switch (nfsstat3 status) { + case NFS3_OK: + CREATE2resok resok; + default: + void; +}; + +struct REMOVE2args { + diropargs2 what; +}; + +struct REMOVE2res { + nfsstat3 status; +}; + +struct RENAME2args { + diropargs2 from; + diropargs2 to; +}; + +struct RENAME2res { + nfsstat3 status; +}; + +struct LINK2args { + fhandle2 from; + diropargs2 to; +}; + +struct LINK2res { + nfsstat3 status; +}; + +struct SYMLINK2args { + diropargs2 from; + path2 to; + sattr2 attributes; +}; + +struct SYMLINK2res { + nfsstat3 status; +}; + +struct MKDIR2args { + diropargs2 where; + sattr2 attributes; +}; + +struct MKDIR2resok { + fhandle2 file; + fattr2 attributes; +}; + +union MKDIR2res switch (nfsstat3 status) { + case NFS3_OK: + MKDIR2resok resok; + default: + void; +}; + +struct RMDIR2args { + diropargs2 what; +}; + +struct RMDIR2res { + nfsstat3 status; +}; + +struct READDIR2args { + fhandle2 dir; + nfscookie2 cookie; + unsigned int count; +}; + +struct READDIR2resok { + entry2 *entries; + bool eof; +}; + +union READDIR2res switch (nfsstat3 status) { + case NFS3_OK: + READDIR2resok resok; + default: + void; +}; + +struct STATFS2args { + fhandle2 dir; +}; + +struct STATFS2resok { + unsigned int tsize; + unsigned int bsize; + unsigned int blocks; + unsigned int bfree; + unsigned int bavail; +}; + +union STATFS2res switch (nfsstat3 status) { + case NFS3_OK: + STATFS2resok resok; + default: + void; +}; + +program NFS_PROGRAM { + version NFS_V2 { + void + NFS2_NULL(void) = 0; + + GETATTR2res + NFS2_GETATTR(GETATTR2args) = 1; + + SETATTR2res + NFS2_SETATTR(SETATTR2args) = 2; + + LOOKUP2res + NFS2_LOOKUP(LOOKUP2args) = 4; + + READLINK2res + NFS2_READLINK(READLINK2args) = 5; + + READ2res + NFS2_READ(READ2args) = 6; + + WRITE2res + NFS2_WRITE(WRITE2args) = 8; + + CREATE2res + NFS2_CREATE(CREATE2args) = 9; + + REMOVE2res + NFS2_REMOVE(REMOVE2args) = 10; + + RENAME2res + NFS2_RENAME(RENAME2args) = 11; + + LINK2res + NFS2_LINK(LINK2args) = 12; + + SYMLINK2res + NFS2_SYMLINK(SYMLINK2args) = 13; + + MKDIR2res + NFS2_MKDIR(MKDIR2args) = 14; + + RMDIR2res + NFS2_RMDIR(RMDIR2args) = 15; + + READDIR2res + NFS2_READDIR(READDIR2args) = 16; + + STATFS2res + NFS2_STATFS(STATFS2args) = 17; + } = 2; + + version NFS_V3 { + void + NFS3_NULL(void) = 0; + + GETATTR3res + NFS3_GETATTR(GETATTR3args) = 1; + + SETATTR3res + NFS3_SETATTR(SETATTR3args) = 2; + + LOOKUP3res + NFS3_LOOKUP(LOOKUP3args) = 3; + + ACCESS3res + NFS3_ACCESS(ACCESS3args) = 4; + + READLINK3res + NFS3_READLINK(READLINK3args) = 5; + + READ3res + NFS3_READ(READ3args) = 6; + + WRITE3res + NFS3_WRITE(WRITE3args) = 7; + + CREATE3res + NFS3_CREATE(CREATE3args) = 8; + + MKDIR3res + NFS3_MKDIR(MKDIR3args) = 9; + + SYMLINK3res + NFS3_SYMLINK(SYMLINK3args) = 10; + + MKNOD3res + NFS3_MKNOD(MKNOD3args) = 11; + + REMOVE3res + NFS3_REMOVE(REMOVE3args) = 12; + + RMDIR3res + NFS3_RMDIR(RMDIR3args) = 13; + + RENAME3res + NFS3_RENAME(RENAME3args) = 14; + + LINK3res + NFS3_LINK(LINK3args) = 15; + + READDIR3res + NFS3_READDIR(READDIR3args) = 16; + + READDIRPLUS3res + NFS3_READDIRPLUS(READDIRPLUS3args) = 17; + + FSSTAT3res + NFS3_FSSTAT(FSSTAT3args) = 18; + + FSINFO3res + NFS3_FSINFO(FSINFO3args) = 19; + + PATHCONF3res + NFS3_PATHCONF(PATHCONF3args) = 20; + + COMMIT3res + NFS3_COMMIT(COMMIT3args) = 21; + } = 3; +} = 100003; + +/* NFS ACL definitions based on wireshark souces and network traces */ +/* NFSACL interface. Uses same port/process as NFS */ + +enum nfsacl_type { + NFSACL_TYPE_USER_OBJ = 0x0001, + NFSACL_TYPE_USER = 0x0002, + NFSACL_TYPE_GROUP_OBJ = 0x0004, + NFSACL_TYPE_GROUP = 0x0008, + NFSACL_TYPE_CLASS_OBJ = 0x0010, + NFSACL_TYPE_CLASS = 0x0020, + NFSACL_TYPE_DEFAULT = 0x1000, + NFSACL_TYPE_DEFAULT_USER_OBJ = 0x1001, + NFSACL_TYPE_DEFAULT_USER = 0x1002, + NFSACL_TYPE_DEFAULT_GROUP_OBJ = 0x1004, + NFSACL_TYPE_DEFAULT_GROUP = 0x1008, + NFSACL_TYPE_DEFAULT_CLASS_OBJ = 0x1010, + NFSACL_TYPE_DEFAULT_OTHER_OBJ = 0x1020 +}; + +const NFSACL_PERM_READ = 0x04; +const NFSACL_PERM_WRITE = 0x02; +const NFSACL_PERM_EXEC = 0x01; + +struct nfsacl_ace { + enum nfsacl_type type; + unsigned int id; + unsigned int perm; +}; + +const NFSACL_MASK_ACL_ENTRY = 0x0001; +const NFSACL_MASK_ACL_COUNT = 0x0002; +const NFSACL_MASK_ACL_DEFAULT_ENTRY = 0x0004; +const NFSACL_MASK_ACL_DEFAULT_COUNT = 0x0008; + +struct GETACL3args { + nfs_fh3 dir; + unsigned int mask; +}; + +struct GETACL3resok { + post_op_attr attr; + unsigned int mask; + unsigned int ace_count; + struct nfsacl_ace ace<>; + unsigned int default_ace_count; + struct nfsacl_ace default_ace<>; +}; + +union GETACL3res switch (nfsstat3 status) { +case NFS3_OK: + GETACL3resok resok; +default: + void; +}; + +struct SETACL3args { + nfs_fh3 dir; + unsigned int mask; + unsigned int ace_count; + struct nfsacl_ace ace<>; + unsigned int default_ace_count; + struct nfsacl_ace default_ace<>; +}; + +struct SETACL3resok { + post_op_attr attr; +}; + +union SETACL3res switch (nfsstat3 status) { +case NFS3_OK: + SETACL3resok resok; +default: + void; +}; + +program NFSACL_PROGRAM { + version NFSACL_V3 { + void + NFSACL3_NULL(void) = 0; + + GETACL3res + NFSACL3_GETACL(GETACL3args) = 1; + + SETACL3res + NFSACL3_SETACL(SETACL3args) = 2; + } = 3; +} = 100227; + +/* NFS MOUNT definitions */ + +const MNTPATHLEN = 1024; /* Maximum bytes in a path name */ +const MNTNAMLEN = 255; /* Maximum bytes in a name */ + +typedef string nfs_dirpath; +typedef string nfs_name; + +enum nfs_mountstat3 { + MNT3_OK = 0, /* no error */ + MNT3ERR_PERM = 1, /* Not owner */ + MNT3ERR_NOENT = 2, /* No such file or directory */ + MNT3ERR_IO = 5, /* I/O error */ + MNT3ERR_ACCES = 13, /* Permission denied */ + MNT3ERR_NOTDIR = 20, /* Not a directory */ + MNT3ERR_INVAL = 22, /* Invalid argument */ + MNT3ERR_NAMETOOLONG = 63, /* Filename too long */ + MNT3ERR_NOTSUPP = 10004, /* Operation not supported */ + MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */ +}; + +typedef struct nfs_mountbody *nfs_mountlist; + +struct nfs_mountbody { + nfs_name ml_hostname; + nfs_dirpath ml_directory; + nfs_mountlist ml_next; +}; + +typedef struct nfs_groupnode *nfs_groups; + +struct nfs_groupnode { + nfs_name gr_name; + nfs_groups gr_next; +}; + +typedef struct nfs_exportnode *nfs_exports; + +struct nfs_exportnode { + nfs_dirpath ex_dir; + nfs_groups ex_groups; + nfs_exports ex_next; +}; + +struct nfs_mountres3_ok { + nfs_fh3 fhandle; + u_int auth_flavors<>; +}; + +union nfs_mountres3 switch (nfs_mountstat3 fhs_status) { + case MNT3_OK: + nfs_mountres3_ok mountinfo; + default: + void; +}; + +enum nfs_mountstat1 { + MNT1_OK = 0, /* no error */ + MNT1ERR_PERM = 1, /* Not owner */ + MNT1ERR_NOENT = 2, /* No such file or directory */ + MNT1ERR_IO = 5, /* I/O error */ + MNT1ERR_ACCES = 13, /* Permission denied */ + MNT1ERR_NOTDIR = 20, /* Not a directory */ + MNT1ERR_INVAL = 22, /* Invalid argument */ + MNT1ERR_NAMETOOLONG = 63, /* Filename too long */ + MNT1ERR_NOTSUPP = 10004, /* Operation not supported */ + MNT1ERR_SERVERFAULT = 10006 /* A failure on the server */ +}; + +const FHSIZE = 32; +typedef opaque nfs_fhandle1[FHSIZE]; + +struct nfs_mountres1_ok { + nfs_fhandle1 fhandle; +}; + +union nfs_mountres1 switch (nfs_mountstat1 fhs_status) { + case MNT1_OK: + nfs_mountres1_ok mountinfo; + default: + void; +}; + +program MOUNT_PROGRAM { + version MOUNT_V1 { + void MOUNT1_NULL(void) = 0; + nfs_mountres1 MOUNT1_MNT(nfs_dirpath) = 1; + nfs_mountlist MOUNT1_DUMP(void) = 2; + void MOUNT1_UMNT(nfs_dirpath) = 3; + void MOUNT1_UMNTALL(void) = 4; + nfs_exports MOUNT1_EXPORT(void) = 5; + } = 1; + version MOUNT_V3 { + void MOUNT3_NULL(void) = 0; + nfs_mountres3 MOUNT3_MNT(nfs_dirpath) = 1; + nfs_mountlist MOUNT3_DUMP(void) = 2; + void MOUNT3_UMNT(nfs_dirpath) = 3; + void MOUNT3_UMNTALL(void) = 4; + nfs_exports MOUNT3_EXPORT(void) = 5; + } = 3; +} = 100005; diff --git a/src/nfs/nfs_xdr.cpp b/src/nfs/nfs_xdr.cpp new file mode 100644 index 000000000..87451293d --- /dev/null +++ b/src/nfs/nfs_xdr.cpp @@ -0,0 +1,2954 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "nfs.h" +#include "xdr_impl_inline.h" + +bool_t +xdr_cookieverf3 (XDR *xdrs, cookieverf3 objp) +{ + + if (!xdr_opaque (xdrs, objp, NFS3_COOKIEVERFSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_cookie3 (XDR *xdrs, cookie3 *objp) +{ + + if (!xdr_uint64_t (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_fh3 (XDR *xdrs, nfs_fh3 *objp) +{ + + if (!xdr_bytes(xdrs, objp, NFS3_FHSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_filename3 (XDR *xdrs, filename3 *objp) +{ + + if (!xdr_string (xdrs, objp, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_diropargs3 (XDR *xdrs, diropargs3 *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->dir)) + return FALSE; + if (!xdr_filename3 (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_ftype3 (XDR *xdrs, ftype3 *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mode3 (XDR *xdrs, mode3 *objp) +{ + + if (!xdr_u_int (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_uid3 (XDR *xdrs, uid3 *objp) +{ + + if (!xdr_u_int (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_gid3 (XDR *xdrs, gid3 *objp) +{ + + if (!xdr_u_int (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_size3 (XDR *xdrs, size3 *objp) +{ + + if (!xdr_uint64_t (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fileid3 (XDR *xdrs, fileid3 *objp) +{ + + if (!xdr_uint64_t (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_specdata3 (XDR *xdrs, specdata3 *objp) +{ + + if (!xdr_u_int (xdrs, &objp->specdata1)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->specdata2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfstime3 (XDR *xdrs, nfstime3 *objp) +{ + + if (!xdr_u_int (xdrs, &objp->seconds)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nseconds)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fattr3 (XDR *xdrs, fattr3 *objp) +{ + + if (!xdr_ftype3 (xdrs, &objp->type)) + return FALSE; + if (!xdr_mode3 (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nlink)) + return FALSE; + if (!xdr_uid3 (xdrs, &objp->uid)) + return FALSE; + if (!xdr_gid3 (xdrs, &objp->gid)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->size)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->used)) + return FALSE; + if (!xdr_specdata3 (xdrs, &objp->rdev)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->fsid)) + return FALSE; + if (!xdr_fileid3 (xdrs, &objp->fileid)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->ctime)) + return FALSE; + return TRUE; +} + +bool_t +xdr_post_op_attr (XDR *xdrs, post_op_attr *objp) +{ + + if (!xdr_bool (xdrs, &objp->attributes_follow)) + return FALSE; + switch (objp->attributes_follow) { + case TRUE: + if (!xdr_fattr3 (xdrs, &objp->attributes)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_nfsstat3 (XDR *xdrs, nfsstat3 *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_stable_how (XDR *xdrs, stable_how *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_offset3 (XDR *xdrs, offset3 *objp) +{ + + if (!xdr_uint64_t (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_count3 (XDR *xdrs, count3 *objp) +{ + + if (!xdr_u_int (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_wcc_attr (XDR *xdrs, wcc_attr *objp) +{ + + if (!xdr_size3 (xdrs, &objp->size)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->ctime)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pre_op_attr (XDR *xdrs, pre_op_attr *objp) +{ + + if (!xdr_bool (xdrs, &objp->attributes_follow)) + return FALSE; + switch (objp->attributes_follow) { + case TRUE: + if (!xdr_wcc_attr (xdrs, &objp->attributes)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_wcc_data (XDR *xdrs, wcc_data *objp) +{ + + if (!xdr_pre_op_attr (xdrs, &objp->before)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->after)) + return FALSE; + return TRUE; +} + +bool_t +xdr_WRITE3args (XDR *xdrs, WRITE3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->file)) + return FALSE; + if (!xdr_offset3 (xdrs, &objp->offset)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->count)) + return FALSE; + if (!xdr_stable_how (xdrs, &objp->stable)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->data, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_writeverf3 (XDR *xdrs, writeverf3 objp) +{ + + if (!xdr_opaque (xdrs, objp, NFS3_WRITEVERFSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_WRITE3resok (XDR *xdrs, WRITE3resok *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->file_wcc)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->count)) + return FALSE; + if (!xdr_stable_how (xdrs, &objp->committed)) + return FALSE; + if (!xdr_writeverf3 (xdrs, objp->verf)) + return FALSE; + return TRUE; +} + +bool_t +xdr_WRITE3resfail (XDR *xdrs, WRITE3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->file_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_WRITE3res (XDR *xdrs, WRITE3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_WRITE3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_WRITE3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_LOOKUP3args (XDR *xdrs, LOOKUP3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->what)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LOOKUP3resok (XDR *xdrs, LOOKUP3resok *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->object)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LOOKUP3resfail (XDR *xdrs, LOOKUP3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LOOKUP3res (XDR *xdrs, LOOKUP3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_LOOKUP3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_LOOKUP3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_COMMIT3args (XDR *xdrs, COMMIT3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->file)) + return FALSE; + if (!xdr_offset3 (xdrs, &objp->offset)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t +xdr_COMMIT3resok (XDR *xdrs, COMMIT3resok *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->file_wcc)) + return FALSE; + if (!xdr_writeverf3 (xdrs, objp->verf)) + return FALSE; + return TRUE; +} + +bool_t +xdr_COMMIT3resfail (XDR *xdrs, COMMIT3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->file_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_COMMIT3res (XDR *xdrs, COMMIT3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_COMMIT3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_COMMIT3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_ACCESS3args (XDR *xdrs, ACCESS3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->object)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->access)) + return FALSE; + return TRUE; +} + +bool_t +xdr_ACCESS3resok (XDR *xdrs, ACCESS3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->access)) + return FALSE; + return TRUE; +} + +bool_t +xdr_ACCESS3resfail (XDR *xdrs, ACCESS3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_ACCESS3res (XDR *xdrs, ACCESS3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_ACCESS3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_ACCESS3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_GETATTR3args (XDR *xdrs, GETATTR3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETATTR3resok (XDR *xdrs, GETATTR3resok *objp) +{ + + if (!xdr_fattr3 (xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETATTR3res (XDR *xdrs, GETATTR3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_GETATTR3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_time_how (XDR *xdrs, time_how *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_set_mode3 (XDR *xdrs, set_mode3 *objp) +{ + + if (!xdr_bool (xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_mode3 (xdrs, &objp->mode)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_set_uid3 (XDR *xdrs, set_uid3 *objp) +{ + + if (!xdr_bool (xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_uid3 (xdrs, &objp->uid)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_set_gid3 (XDR *xdrs, set_gid3 *objp) +{ + + if (!xdr_bool (xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_gid3 (xdrs, &objp->gid)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_set_size3 (XDR *xdrs, set_size3 *objp) +{ + + if (!xdr_bool (xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_size3 (xdrs, &objp->size)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_set_atime (XDR *xdrs, set_atime *objp) +{ + + if (!xdr_time_how (xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case SET_TO_CLIENT_TIME: + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_set_mtime (XDR *xdrs, set_mtime *objp) +{ + + if (!xdr_time_how (xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case SET_TO_CLIENT_TIME: + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_sattr3 (XDR *xdrs, sattr3 *objp) +{ + + if (!xdr_set_mode3 (xdrs, &objp->mode)) + return FALSE; + if (!xdr_set_uid3 (xdrs, &objp->uid)) + return FALSE; + if (!xdr_set_gid3 (xdrs, &objp->gid)) + return FALSE; + if (!xdr_set_size3 (xdrs, &objp->size)) + return FALSE; + if (!xdr_set_atime (xdrs, &objp->atime)) + return FALSE; + if (!xdr_set_mtime (xdrs, &objp->mtime)) + return FALSE; + return TRUE; +} + +bool_t +xdr_createmode3 (XDR *xdrs, createmode3 *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_createverf3 (XDR *xdrs, createverf3 objp) +{ + + if (!xdr_opaque (xdrs, objp, NFS3_CREATEVERFSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_createhow3 (XDR *xdrs, createhow3 *objp) +{ + + if (!xdr_createmode3 (xdrs, &objp->mode)) + return FALSE; + switch (objp->mode) { + case NFS_UNCHECKED: + if (!xdr_sattr3 (xdrs, &objp->obj_attributes)) + return FALSE; + break; + case NFS_GUARDED: + if (!xdr_sattr3 (xdrs, &objp->g_obj_attributes)) + return FALSE; + break; + case NFS_EXCLUSIVE: + if (!xdr_createverf3 (xdrs, objp->verf)) + return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_CREATE3args (XDR *xdrs, CREATE3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->where)) + return FALSE; + if (!xdr_createhow3 (xdrs, &objp->how)) + return FALSE; + return TRUE; +} + +bool_t +xdr_post_op_fh3 (XDR *xdrs, post_op_fh3 *objp) +{ + + if (!xdr_bool (xdrs, &objp->handle_follows)) + return FALSE; + switch (objp->handle_follows) { + case TRUE: + if (!xdr_nfs_fh3 (xdrs, &objp->handle)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_CREATE3resok (XDR *xdrs, CREATE3resok *objp) +{ + + if (!xdr_post_op_fh3 (xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_CREATE3resfail (XDR *xdrs, CREATE3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_CREATE3res (XDR *xdrs, CREATE3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_CREATE3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_CREATE3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_REMOVE3args (XDR *xdrs, REMOVE3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t +xdr_REMOVE3resok (XDR *xdrs, REMOVE3resok *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_REMOVE3resfail (XDR *xdrs, REMOVE3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_REMOVE3res (XDR *xdrs, REMOVE3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_REMOVE3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_REMOVE3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_READ3args (XDR *xdrs, READ3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->file)) + return FALSE; + if (!xdr_offset3 (xdrs, &objp->offset)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READ3resok (XDR *xdrs, READ3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->count)) + return FALSE; + if (!xdr_bool (xdrs, &objp->eof)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->data, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READ3resfail (XDR *xdrs, READ3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READ3res (XDR *xdrs, READ3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READ3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_READ3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_FSINFO3args (XDR *xdrs, FSINFO3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->fsroot)) + return FALSE; + return TRUE; +} + +bool_t +xdr_FSINFO3resok (XDR *xdrs, FSINFO3resok *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->rtmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rtpref)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rtmult)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtpref)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtmult)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->dtpref)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->rtmax); + IXDR_PUT_U_LONG(buf, objp->rtpref); + IXDR_PUT_U_LONG(buf, objp->rtmult); + IXDR_PUT_U_LONG(buf, objp->wtmax); + IXDR_PUT_U_LONG(buf, objp->wtpref); + IXDR_PUT_U_LONG(buf, objp->wtmult); + IXDR_PUT_U_LONG(buf, objp->dtpref); + } + if (!xdr_size3 (xdrs, &objp->maxfilesize)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->time_delta)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->properties)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->rtmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rtpref)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rtmult)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtpref)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtmult)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->dtpref)) + return FALSE; + + } else { + objp->rtmax = IXDR_GET_U_LONG(buf); + objp->rtpref = IXDR_GET_U_LONG(buf); + objp->rtmult = IXDR_GET_U_LONG(buf); + objp->wtmax = IXDR_GET_U_LONG(buf); + objp->wtpref = IXDR_GET_U_LONG(buf); + objp->wtmult = IXDR_GET_U_LONG(buf); + objp->dtpref = IXDR_GET_U_LONG(buf); + } + if (!xdr_size3 (xdrs, &objp->maxfilesize)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->time_delta)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->properties)) + return FALSE; + return TRUE; + } + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rtmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rtpref)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rtmult)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtpref)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->wtmult)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->dtpref)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->maxfilesize)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->time_delta)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->properties)) + return FALSE; + return TRUE; +} + +bool_t +xdr_FSINFO3resfail (XDR *xdrs, FSINFO3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_FSINFO3res (XDR *xdrs, FSINFO3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_FSINFO3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_FSINFO3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_FSSTAT3args (XDR *xdrs, FSSTAT3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->fsroot)) + return FALSE; + return TRUE; +} + +bool_t +xdr_FSSTAT3resok (XDR *xdrs, FSSTAT3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->tbytes)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->fbytes)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->abytes)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->tfiles)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->ffiles)) + return FALSE; + if (!xdr_size3 (xdrs, &objp->afiles)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->invarsec)) + return FALSE; + return TRUE; +} + +bool_t +xdr_FSSTAT3resfail (XDR *xdrs, FSSTAT3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_FSSTAT3res (XDR *xdrs, FSSTAT3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_FSSTAT3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_FSSTAT3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_PATHCONF3args (XDR *xdrs, PATHCONF3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PATHCONF3resok (XDR *xdrs, PATHCONF3resok *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->linkmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->name_max)) + return FALSE; + if (!xdr_bool (xdrs, &objp->no_trunc)) + return FALSE; + if (!xdr_bool (xdrs, &objp->chown_restricted)) + return FALSE; + if (!xdr_bool (xdrs, &objp->case_insensitive)) + return FALSE; + if (!xdr_bool (xdrs, &objp->case_preserving)) + return FALSE; + } else { + IXDR_PUT_U_LONG(buf, objp->linkmax); + IXDR_PUT_U_LONG(buf, objp->name_max); + IXDR_PUT_BOOL(buf, objp->no_trunc); + IXDR_PUT_BOOL(buf, objp->chown_restricted); + IXDR_PUT_BOOL(buf, objp->case_insensitive); + IXDR_PUT_BOOL(buf, objp->case_preserving); + } + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->linkmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->name_max)) + return FALSE; + if (!xdr_bool (xdrs, &objp->no_trunc)) + return FALSE; + if (!xdr_bool (xdrs, &objp->chown_restricted)) + return FALSE; + if (!xdr_bool (xdrs, &objp->case_insensitive)) + return FALSE; + if (!xdr_bool (xdrs, &objp->case_preserving)) + return FALSE; + } else { + objp->linkmax = IXDR_GET_U_LONG(buf); + objp->name_max = IXDR_GET_U_LONG(buf); + objp->no_trunc = IXDR_GET_BOOL(buf); + objp->chown_restricted = IXDR_GET_BOOL(buf); + objp->case_insensitive = IXDR_GET_BOOL(buf); + objp->case_preserving = IXDR_GET_BOOL(buf); + } + return TRUE; + } + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->linkmax)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->name_max)) + return FALSE; + if (!xdr_bool (xdrs, &objp->no_trunc)) + return FALSE; + if (!xdr_bool (xdrs, &objp->chown_restricted)) + return FALSE; + if (!xdr_bool (xdrs, &objp->case_insensitive)) + return FALSE; + if (!xdr_bool (xdrs, &objp->case_preserving)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PATHCONF3resfail (XDR *xdrs, PATHCONF3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PATHCONF3res (XDR *xdrs, PATHCONF3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_PATHCONF3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_PATHCONF3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_nfspath3 (XDR *xdrs, nfspath3 *objp) +{ + + if (!xdr_string (xdrs, objp, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_symlinkdata3 (XDR *xdrs, symlinkdata3 *objp) +{ + + if (!xdr_sattr3 (xdrs, &objp->symlink_attributes)) + return FALSE; + if (!xdr_nfspath3 (xdrs, &objp->symlink_data)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SYMLINK3args (XDR *xdrs, SYMLINK3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->where)) + return FALSE; + if (!xdr_symlinkdata3 (xdrs, &objp->symlink)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SYMLINK3resok (XDR *xdrs, SYMLINK3resok *objp) +{ + + if (!xdr_post_op_fh3 (xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SYMLINK3resfail (XDR *xdrs, SYMLINK3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SYMLINK3res (XDR *xdrs, SYMLINK3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_SYMLINK3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_SYMLINK3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_READLINK3args (XDR *xdrs, READLINK3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->symlink)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READLINK3resok (XDR *xdrs, READLINK3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->symlink_attributes)) + return FALSE; + if (!xdr_nfspath3 (xdrs, &objp->data)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READLINK3resfail (XDR *xdrs, READLINK3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->symlink_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READLINK3res (XDR *xdrs, READLINK3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READLINK3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_READLINK3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_devicedata3 (XDR *xdrs, devicedata3 *objp) +{ + + if (!xdr_sattr3 (xdrs, &objp->dev_attributes)) + return FALSE; + if (!xdr_specdata3 (xdrs, &objp->spec)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mknoddata3 (XDR *xdrs, mknoddata3 *objp) +{ + + if (!xdr_ftype3 (xdrs, &objp->type)) + return FALSE; + switch (objp->type) { + case NF3CHR: + if (!xdr_devicedata3 (xdrs, &objp->chr_device)) + return FALSE; + break; + case NF3BLK: + if (!xdr_devicedata3 (xdrs, &objp->blk_device)) + return FALSE; + break; + case NF3SOCK: + if (!xdr_sattr3 (xdrs, &objp->sock_attributes)) + return FALSE; + break; + case NF3FIFO: + if (!xdr_sattr3 (xdrs, &objp->pipe_attributes)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_MKNOD3args (XDR *xdrs, MKNOD3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->where)) + return FALSE; + if (!xdr_mknoddata3 (xdrs, &objp->what)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKNOD3resok (XDR *xdrs, MKNOD3resok *objp) +{ + + if (!xdr_post_op_fh3 (xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKNOD3resfail (XDR *xdrs, MKNOD3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKNOD3res (XDR *xdrs, MKNOD3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_MKNOD3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_MKNOD3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_MKDIR3args (XDR *xdrs, MKDIR3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->where)) + return FALSE; + if (!xdr_sattr3 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKDIR3resok (XDR *xdrs, MKDIR3resok *objp) +{ + + if (!xdr_post_op_fh3 (xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKDIR3resfail (XDR *xdrs, MKDIR3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKDIR3res (XDR *xdrs, MKDIR3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_MKDIR3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_MKDIR3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_RMDIR3args (XDR *xdrs, RMDIR3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RMDIR3resok (XDR *xdrs, RMDIR3resok *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RMDIR3resfail (XDR *xdrs, RMDIR3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RMDIR3res (XDR *xdrs, RMDIR3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_RMDIR3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_RMDIR3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_RENAME3args (XDR *xdrs, RENAME3args *objp) +{ + + if (!xdr_diropargs3 (xdrs, &objp->from)) + return FALSE; + if (!xdr_diropargs3 (xdrs, &objp->to)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RENAME3resok (XDR *xdrs, RENAME3resok *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->fromdir_wcc)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->todir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RENAME3resfail (XDR *xdrs, RENAME3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->fromdir_wcc)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->todir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RENAME3res (XDR *xdrs, RENAME3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_RENAME3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_RENAME3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_READDIRPLUS3args (XDR *xdrs, READDIRPLUS3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->dir)) + return FALSE; + if (!xdr_cookie3 (xdrs, &objp->cookie)) + return FALSE; + if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->dircount)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->maxcount)) + return FALSE; + return TRUE; +} + +bool_t +xdr_entryplus3 (XDR *xdrs, entryplus3 *objp) +{ + + if (!xdr_fileid3 (xdrs, &objp->fileid)) + return FALSE; + if (!xdr_filename3 (xdrs, &objp->name)) + return FALSE; + if (!xdr_cookie3 (xdrs, &objp->cookie)) + return FALSE; + if (!xdr_post_op_attr (xdrs, &objp->name_attributes)) + return FALSE; + if (!xdr_post_op_fh3 (xdrs, &objp->name_handle)) + return FALSE; + if (!xdr_pointer (xdrs, (char **)&objp->nextentry, sizeof (entryplus3), (xdrproc_t) xdr_entryplus3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_dirlistplus3 (XDR *xdrs, dirlistplus3 *objp) +{ + + if (!xdr_pointer (xdrs, (char **)&objp->entries, sizeof (entryplus3), (xdrproc_t) xdr_entryplus3)) + return FALSE; + if (!xdr_bool (xdrs, &objp->eof)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIRPLUS3resok (XDR *xdrs, READDIRPLUS3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) + return FALSE; + if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_dirlistplus3 (xdrs, &objp->reply)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIRPLUS3resfail (XDR *xdrs, READDIRPLUS3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIRPLUS3res (XDR *xdrs, READDIRPLUS3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READDIRPLUS3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_READDIRPLUS3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_READDIR3args (XDR *xdrs, READDIR3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->dir)) + return FALSE; + if (!xdr_cookie3 (xdrs, &objp->cookie)) + return FALSE; + if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_count3 (xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t +xdr_entry3 (XDR *xdrs, entry3 *objp) +{ + + if (!xdr_fileid3 (xdrs, &objp->fileid)) + return FALSE; + if (!xdr_filename3 (xdrs, &objp->name)) + return FALSE; + if (!xdr_cookie3 (xdrs, &objp->cookie)) + return FALSE; + if (!xdr_pointer (xdrs, (char **)&objp->nextentry, sizeof (entry3), (xdrproc_t) xdr_entry3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_dirlist3 (XDR *xdrs, dirlist3 *objp) +{ + + if (!xdr_pointer (xdrs, (char **)&objp->entries, sizeof (entry3), (xdrproc_t) xdr_entry3)) + return FALSE; + if (!xdr_bool (xdrs, &objp->eof)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIR3resok (XDR *xdrs, READDIR3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) + return FALSE; + if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_dirlist3 (xdrs, &objp->reply)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIR3resfail (XDR *xdrs, READDIR3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIR3res (XDR *xdrs, READDIR3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READDIR3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_READDIR3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_LINK3args (XDR *xdrs, LINK3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->file)) + return FALSE; + if (!xdr_diropargs3 (xdrs, &objp->link)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LINK3resok (XDR *xdrs, LINK3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->linkdir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LINK3resfail (XDR *xdrs, LINK3resfail *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) + return FALSE; + if (!xdr_wcc_data (xdrs, &objp->linkdir_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LINK3res (XDR *xdrs, LINK3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_LINK3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_LINK3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_sattrguard3 (XDR *xdrs, sattrguard3 *objp) +{ + + if (!xdr_bool (xdrs, &objp->check)) + return FALSE; + switch (objp->check) { + case TRUE: + if (!xdr_nfstime3 (xdrs, &objp->obj_ctime)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_SETATTR3args (XDR *xdrs, SETATTR3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->object)) + return FALSE; + if (!xdr_sattr3 (xdrs, &objp->new_attributes)) + return FALSE; + if (!xdr_sattrguard3 (xdrs, &objp->guard)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SETATTR3resok (XDR *xdrs, SETATTR3resok *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->obj_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SETATTR3resfail (XDR *xdrs, SETATTR3resfail *objp) +{ + + if (!xdr_wcc_data (xdrs, &objp->obj_wcc)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SETATTR3res (XDR *xdrs, SETATTR3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_SETATTR3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + if (!xdr_SETATTR3resfail (xdrs, &objp->resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_fhandle2 (XDR *xdrs, fhandle2 objp) +{ + + if (!xdr_opaque (xdrs, objp, FHSIZE2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_ftype2 (XDR *xdrs, ftype2 *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fattr2 (XDR *xdrs, fattr2 *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_ftype2 (xdrs, &objp->type)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nlink)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocksize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rdev)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fsid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->mode); + IXDR_PUT_U_LONG(buf, objp->nlink); + IXDR_PUT_U_LONG(buf, objp->uid); + IXDR_PUT_U_LONG(buf, objp->gid); + IXDR_PUT_U_LONG(buf, objp->size); + IXDR_PUT_U_LONG(buf, objp->blocksize); + IXDR_PUT_U_LONG(buf, objp->rdev); + IXDR_PUT_U_LONG(buf, objp->blocks); + IXDR_PUT_U_LONG(buf, objp->fsid); + IXDR_PUT_U_LONG(buf, objp->fileid); + } + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->ctime)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_ftype2 (xdrs, &objp->type)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nlink)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocksize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rdev)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fsid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + + } else { + objp->mode = IXDR_GET_U_LONG(buf); + objp->nlink = IXDR_GET_U_LONG(buf); + objp->uid = IXDR_GET_U_LONG(buf); + objp->gid = IXDR_GET_U_LONG(buf); + objp->size = IXDR_GET_U_LONG(buf); + objp->blocksize = IXDR_GET_U_LONG(buf); + objp->rdev = IXDR_GET_U_LONG(buf); + objp->blocks = IXDR_GET_U_LONG(buf); + objp->fsid = IXDR_GET_U_LONG(buf); + objp->fileid = IXDR_GET_U_LONG(buf); + } + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->ctime)) + return FALSE; + return TRUE; + } + + if (!xdr_ftype2 (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->nlink)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocksize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->rdev)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fsid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->ctime)) + return FALSE; + return TRUE; +} + +bool_t +xdr_sattr2 (XDR *xdrs, sattr2 *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->mode); + IXDR_PUT_U_LONG(buf, objp->uid); + IXDR_PUT_U_LONG(buf, objp->gid); + IXDR_PUT_U_LONG(buf, objp->size); + } + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + + } else { + objp->mode = IXDR_GET_U_LONG(buf); + objp->uid = IXDR_GET_U_LONG(buf); + objp->gid = IXDR_GET_U_LONG(buf); + objp->size = IXDR_GET_U_LONG(buf); + } + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->gid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->size)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3 (xdrs, &objp->mtime)) + return FALSE; + return TRUE; +} + +bool_t +xdr_filename2 (XDR *xdrs, filename2 *objp) +{ + + if (!xdr_string (xdrs, objp, MAXNAMLEN2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_path2 (XDR *xdrs, path2 *objp) +{ + + if (!xdr_string (xdrs, objp, MAXPATHLEN2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfsdata2 (XDR *xdrs, nfsdata2 *objp) +{ + + if (!xdr_bytes(xdrs, objp, NFSMAXDATA2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfscookie2 (XDR *xdrs, nfscookie2 objp) +{ + + if (!xdr_opaque (xdrs, objp, NFSCOOKIESIZE2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_entry2 (XDR *xdrs, entry2 *objp) +{ + + if (!xdr_u_int (xdrs, &objp->fileid)) + return FALSE; + if (!xdr_filename2 (xdrs, &objp->name)) + return FALSE; + if (!xdr_nfscookie2 (xdrs, objp->cookie)) + return FALSE; + if (!xdr_pointer (xdrs, (char **)&objp->nextentry, sizeof (entry2), (xdrproc_t) xdr_entry2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_diropargs2 (XDR *xdrs, diropargs2 *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->dir)) + return FALSE; + if (!xdr_filename2 (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETATTR2args (XDR *xdrs, GETATTR2args *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->fhandle)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETATTR2resok (XDR *xdrs, GETATTR2resok *objp) +{ + + if (!xdr_fattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETATTR2res (XDR *xdrs, GETATTR2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_GETATTR2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_SETATTR2args (XDR *xdrs, SETATTR2args *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->fhandle)) + return FALSE; + if (!xdr_sattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SETATTR2resok (XDR *xdrs, SETATTR2resok *objp) +{ + + if (!xdr_fattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SETATTR2res (XDR *xdrs, SETATTR2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_SETATTR2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_LOOKUP2args (XDR *xdrs, LOOKUP2args *objp) +{ + + if (!xdr_diropargs2 (xdrs, &objp->what)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LOOKUP2resok (XDR *xdrs, LOOKUP2resok *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + if (!xdr_fattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LOOKUP2res (XDR *xdrs, LOOKUP2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_LOOKUP2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_READLINK2args (XDR *xdrs, READLINK2args *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READLINK2resok (XDR *xdrs, READLINK2resok *objp) +{ + + if (!xdr_path2 (xdrs, &objp->data)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READLINK2res (XDR *xdrs, READLINK2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READLINK2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_READ2args (XDR *xdrs, READ2args *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->count)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READ2resok (XDR *xdrs, READ2resok *objp) +{ + + if (!xdr_fattr2 (xdrs, &objp->attributes)) + return FALSE; + if (!xdr_nfsdata2 (xdrs, &objp->data)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READ2res (XDR *xdrs, READ2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READ2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_WRITE2args (XDR *xdrs, WRITE2args *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->beginoffset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->beginoffset); + IXDR_PUT_U_LONG(buf, objp->offset); + IXDR_PUT_U_LONG(buf, objp->totalcount); + } + if (!xdr_nfsdata2 (xdrs, &objp->data)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + if (1) { + if (!xdr_u_int (xdrs, &objp->beginoffset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + + } else { + objp->beginoffset = IXDR_GET_U_LONG(buf); + objp->offset = IXDR_GET_U_LONG(buf); + objp->totalcount = IXDR_GET_U_LONG(buf); + } + if (!xdr_nfsdata2 (xdrs, &objp->data)) + return FALSE; + return TRUE; + } + + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->beginoffset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->offset)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->totalcount)) + return FALSE; + if (!xdr_nfsdata2 (xdrs, &objp->data)) + return FALSE; + return TRUE; +} + +bool_t +xdr_WRITE2resok (XDR *xdrs, WRITE2resok *objp) +{ + + if (!xdr_fattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_WRITE2res (XDR *xdrs, WRITE2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_WRITE2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_CREATE2args (XDR *xdrs, CREATE2args *objp) +{ + + if (!xdr_diropargs2 (xdrs, &objp->where)) + return FALSE; + if (!xdr_sattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_CREATE2resok (XDR *xdrs, CREATE2resok *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + if (!xdr_fattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_CREATE2res (XDR *xdrs, CREATE2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_CREATE2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_REMOVE2args (XDR *xdrs, REMOVE2args *objp) +{ + + if (!xdr_diropargs2 (xdrs, &objp->what)) + return FALSE; + return TRUE; +} + +bool_t +xdr_REMOVE2res (XDR *xdrs, REMOVE2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RENAME2args (XDR *xdrs, RENAME2args *objp) +{ + + if (!xdr_diropargs2 (xdrs, &objp->from)) + return FALSE; + if (!xdr_diropargs2 (xdrs, &objp->to)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RENAME2res (XDR *xdrs, RENAME2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LINK2args (XDR *xdrs, LINK2args *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->from)) + return FALSE; + if (!xdr_diropargs2 (xdrs, &objp->to)) + return FALSE; + return TRUE; +} + +bool_t +xdr_LINK2res (XDR *xdrs, LINK2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SYMLINK2args (XDR *xdrs, SYMLINK2args *objp) +{ + + if (!xdr_diropargs2 (xdrs, &objp->from)) + return FALSE; + if (!xdr_path2 (xdrs, &objp->to)) + return FALSE; + if (!xdr_sattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SYMLINK2res (XDR *xdrs, SYMLINK2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKDIR2args (XDR *xdrs, MKDIR2args *objp) +{ + + if (!xdr_diropargs2 (xdrs, &objp->where)) + return FALSE; + if (!xdr_sattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKDIR2resok (XDR *xdrs, MKDIR2resok *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->file)) + return FALSE; + if (!xdr_fattr2 (xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_MKDIR2res (XDR *xdrs, MKDIR2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_MKDIR2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_RMDIR2args (XDR *xdrs, RMDIR2args *objp) +{ + + if (!xdr_diropargs2 (xdrs, &objp->what)) + return FALSE; + return TRUE; +} + +bool_t +xdr_RMDIR2res (XDR *xdrs, RMDIR2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIR2args (XDR *xdrs, READDIR2args *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->dir)) + return FALSE; + if (!xdr_nfscookie2 (xdrs, objp->cookie)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIR2resok (XDR *xdrs, READDIR2resok *objp) +{ + + if (!xdr_pointer (xdrs, (char **)&objp->entries, sizeof (entry2), (xdrproc_t) xdr_entry2)) + return FALSE; + if (!xdr_bool (xdrs, &objp->eof)) + return FALSE; + return TRUE; +} + +bool_t +xdr_READDIR2res (XDR *xdrs, READDIR2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READDIR2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_STATFS2args (XDR *xdrs, STATFS2args *objp) +{ + + if (!xdr_fhandle2 (xdrs, objp->dir)) + return FALSE; + return TRUE; +} + +bool_t +xdr_STATFS2resok (XDR *xdrs, STATFS2resok *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->tsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bfree)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bavail)) + return FALSE; + } else { + IXDR_PUT_U_LONG(buf, objp->tsize); + IXDR_PUT_U_LONG(buf, objp->bsize); + IXDR_PUT_U_LONG(buf, objp->blocks); + IXDR_PUT_U_LONG(buf, objp->bfree); + IXDR_PUT_U_LONG(buf, objp->bavail); + } + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->tsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bfree)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bavail)) + return FALSE; + } else { + objp->tsize = IXDR_GET_U_LONG(buf); + objp->bsize = IXDR_GET_U_LONG(buf); + objp->blocks = IXDR_GET_U_LONG(buf); + objp->bfree = IXDR_GET_U_LONG(buf); + objp->bavail = IXDR_GET_U_LONG(buf); + } + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->tsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bsize)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->blocks)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bfree)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->bavail)) + return FALSE; + return TRUE; +} + +bool_t +xdr_STATFS2res (XDR *xdrs, STATFS2res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_STATFS2resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_nfsacl_type (XDR *xdrs, nfsacl_type *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfsacl_ace (XDR *xdrs, nfsacl_ace *objp) +{ + + if (!xdr_nfsacl_type (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->id)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->perm)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETACL3args (XDR *xdrs, GETACL3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->dir)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->mask)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETACL3resok (XDR *xdrs, GETACL3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->attr)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->mask)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->ace_count)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->ace.ace_val, (u_int *) &objp->ace.ace_len, ~0, + sizeof (nfsacl_ace), (xdrproc_t) xdr_nfsacl_ace)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->default_ace_count)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->default_ace.default_ace_val, (u_int *) &objp->default_ace.default_ace_len, ~0, + sizeof (nfsacl_ace), (xdrproc_t) xdr_nfsacl_ace)) + return FALSE; + return TRUE; +} + +bool_t +xdr_GETACL3res (XDR *xdrs, GETACL3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_GETACL3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_SETACL3args (XDR *xdrs, SETACL3args *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->dir)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->mask)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->ace_count)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->ace.ace_val, (u_int *) &objp->ace.ace_len, ~0, + sizeof (nfsacl_ace), (xdrproc_t) xdr_nfsacl_ace)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->default_ace_count)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->default_ace.default_ace_val, (u_int *) &objp->default_ace.default_ace_len, ~0, + sizeof (nfsacl_ace), (xdrproc_t) xdr_nfsacl_ace)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SETACL3resok (XDR *xdrs, SETACL3resok *objp) +{ + + if (!xdr_post_op_attr (xdrs, &objp->attr)) + return FALSE; + return TRUE; +} + +bool_t +xdr_SETACL3res (XDR *xdrs, SETACL3res *objp) +{ + + if (!xdr_nfsstat3 (xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_SETACL3resok (xdrs, &objp->resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_nfs_dirpath (XDR *xdrs, nfs_dirpath *objp) +{ + + if (!xdr_string (xdrs, objp, MNTPATHLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_name (XDR *xdrs, nfs_name *objp) +{ + + if (!xdr_string (xdrs, objp, MNTNAMLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_mountstat3 (XDR *xdrs, nfs_mountstat3 *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_mountlist (XDR *xdrs, nfs_mountlist *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct nfs_mountbody), (xdrproc_t) xdr_nfs_mountbody)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_mountbody (XDR *xdrs, nfs_mountbody *objp) +{ + + if (!xdr_nfs_name (xdrs, &objp->ml_hostname)) + return FALSE; + if (!xdr_nfs_dirpath (xdrs, &objp->ml_directory)) + return FALSE; + if (!xdr_nfs_mountlist (xdrs, &objp->ml_next)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_groups (XDR *xdrs, nfs_groups *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct nfs_groupnode), (xdrproc_t) xdr_nfs_groupnode)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_groupnode (XDR *xdrs, nfs_groupnode *objp) +{ + + if (!xdr_nfs_name (xdrs, &objp->gr_name)) + return FALSE; + if (!xdr_nfs_groups (xdrs, &objp->gr_next)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_exports (XDR *xdrs, nfs_exports *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct nfs_exportnode), (xdrproc_t) xdr_nfs_exportnode)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_exportnode (XDR *xdrs, nfs_exportnode *objp) +{ + + if (!xdr_nfs_dirpath (xdrs, &objp->ex_dir)) + return FALSE; + if (!xdr_nfs_groups (xdrs, &objp->ex_groups)) + return FALSE; + if (!xdr_nfs_exports (xdrs, &objp->ex_next)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_mountres3_ok (XDR *xdrs, nfs_mountres3_ok *objp) +{ + + if (!xdr_nfs_fh3 (xdrs, &objp->fhandle)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->auth_flavors.auth_flavors_val, (u_int *) &objp->auth_flavors.auth_flavors_len, ~0, + sizeof (u_int), (xdrproc_t) xdr_u_int)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_mountres3 (XDR *xdrs, nfs_mountres3 *objp) +{ + + if (!xdr_nfs_mountstat3 (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case MNT3_OK: + if (!xdr_nfs_mountres3_ok (xdrs, &objp->mountinfo)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_nfs_mountstat1 (XDR *xdrs, nfs_mountstat1 *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_fhandle1 (XDR *xdrs, nfs_fhandle1 objp) +{ + + if (!xdr_opaque (xdrs, objp, FHSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_mountres1_ok (XDR *xdrs, nfs_mountres1_ok *objp) +{ + + if (!xdr_nfs_fhandle1 (xdrs, objp->fhandle)) + return FALSE; + return TRUE; +} + +bool_t +xdr_nfs_mountres1 (XDR *xdrs, nfs_mountres1 *objp) +{ + + if (!xdr_nfs_mountstat1 (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case MNT1_OK: + if (!xdr_nfs_mountres1_ok (xdrs, &objp->mountinfo)) + return FALSE; + break; + default: + break; + } + return TRUE; +} diff --git a/src/nfs/portmap.h b/src/nfs/portmap.h new file mode 100644 index 000000000..90a09caa5 --- /dev/null +++ b/src/nfs/portmap.h @@ -0,0 +1,190 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _PORTMAP_H_RPCGEN +#define _PORTMAP_H_RPCGEN + +#include "xdr_impl.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define PMAP_PORT 111 + +struct pmap2_mapping { + u_int prog; + u_int vers; + u_int prot; + u_int port; +}; +typedef struct pmap2_mapping pmap2_mapping; + +struct pmap2_call_args { + u_int prog; + u_int vers; + u_int proc; + xdr_string_t args; +}; +typedef struct pmap2_call_args pmap2_call_args; + +struct pmap2_call_result { + u_int port; + xdr_string_t res; +}; +typedef struct pmap2_call_result pmap2_call_result; + +struct pmap2_mapping_list { + pmap2_mapping map; + struct pmap2_mapping_list *next; +}; +typedef struct pmap2_mapping_list pmap2_mapping_list; + +struct pmap2_dump_result { + struct pmap2_mapping_list *list; +}; +typedef struct pmap2_dump_result pmap2_dump_result; + +struct pmap3_string_result { + xdr_string_t addr; +}; +typedef struct pmap3_string_result pmap3_string_result; + +struct pmap3_mapping { + u_int prog; + u_int vers; + xdr_string_t netid; + xdr_string_t addr; + xdr_string_t owner; +}; +typedef struct pmap3_mapping pmap3_mapping; + +struct pmap3_mapping_list { + pmap3_mapping map; + struct pmap3_mapping_list *next; +}; +typedef struct pmap3_mapping_list pmap3_mapping_list; + +struct pmap3_dump_result { + struct pmap3_mapping_list *list; +}; +typedef struct pmap3_dump_result pmap3_dump_result; + +struct pmap3_call_args { + u_int prog; + u_int vers; + u_int proc; + xdr_string_t args; +}; +typedef struct pmap3_call_args pmap3_call_args; + +struct pmap3_call_result { + u_int port; + xdr_string_t res; +}; +typedef struct pmap3_call_result pmap3_call_result; + +struct pmap3_netbuf { + u_int maxlen; + xdr_string_t buf; +}; +typedef struct pmap3_netbuf pmap3_netbuf; + +typedef pmap2_mapping PMAP2SETargs; + +typedef pmap2_mapping PMAP2UNSETargs; + +typedef pmap2_mapping PMAP2GETPORTargs; + +typedef pmap2_call_args PMAP2CALLITargs; + +typedef pmap2_call_result PMAP2CALLITres; + +typedef pmap2_dump_result PMAP2DUMPres; + +typedef pmap3_mapping PMAP3SETargs; + +typedef pmap3_mapping PMAP3UNSETargs; + +typedef pmap3_mapping PMAP3GETADDRargs; + +typedef pmap3_string_result PMAP3GETADDRres; + +typedef pmap3_dump_result PMAP3DUMPres; + +typedef pmap3_call_result PMAP3CALLITargs; + +typedef pmap3_call_result PMAP3CALLITres; + +typedef pmap3_netbuf PMAP3UADDR2TADDRres; + +typedef pmap3_netbuf PMAP3TADDR2UADDRargs; + +typedef pmap3_string_result PMAP3TADDR2UADDRres; + +#define PMAP_PROGRAM 100000 +#define PMAP_V2 2 + + +#define PMAP2_NULL 0 +#define PMAP2_SET 1 +#define PMAP2_UNSET 2 +#define PMAP2_GETPORT 3 +#define PMAP2_DUMP 4 +#define PMAP2_CALLIT 5 + +#define PMAP_V3 3 + + +#define PMAP3_NULL 0 +#define PMAP3_SET 1 +#define PMAP3_UNSET 2 +#define PMAP3_GETADDR 3 +#define PMAP3_DUMP 4 +#define PMAP3_CALLIT 5 +#define PMAP3_GETTIME 6 +#define PMAP3_UADDR2TADDR 7 +#define PMAP3_TADDR2UADDR 8 + + +/* the xdr functions */ + + +extern bool_t xdr_pmap2_mapping (XDR *, pmap2_mapping*); +extern bool_t xdr_pmap2_call_args (XDR *, pmap2_call_args*); +extern bool_t xdr_pmap2_call_result (XDR *, pmap2_call_result*); +extern bool_t xdr_pmap2_mapping_list (XDR *, pmap2_mapping_list*); +extern bool_t xdr_pmap2_dump_result (XDR *, pmap2_dump_result*); +extern bool_t xdr_pmap3_string_result (XDR *, pmap3_string_result*); +extern bool_t xdr_pmap3_mapping (XDR *, pmap3_mapping*); +extern bool_t xdr_pmap3_mapping_list (XDR *, pmap3_mapping_list*); +extern bool_t xdr_pmap3_dump_result (XDR *, pmap3_dump_result*); +extern bool_t xdr_pmap3_call_args (XDR *, pmap3_call_args*); +extern bool_t xdr_pmap3_call_result (XDR *, pmap3_call_result*); +extern bool_t xdr_pmap3_netbuf (XDR *, pmap3_netbuf*); +extern bool_t xdr_PMAP2SETargs (XDR *, PMAP2SETargs*); +extern bool_t xdr_PMAP2UNSETargs (XDR *, PMAP2UNSETargs*); +extern bool_t xdr_PMAP2GETPORTargs (XDR *, PMAP2GETPORTargs*); +extern bool_t xdr_PMAP2CALLITargs (XDR *, PMAP2CALLITargs*); +extern bool_t xdr_PMAP2CALLITres (XDR *, PMAP2CALLITres*); +extern bool_t xdr_PMAP2DUMPres (XDR *, PMAP2DUMPres*); +extern bool_t xdr_PMAP3SETargs (XDR *, PMAP3SETargs*); +extern bool_t xdr_PMAP3UNSETargs (XDR *, PMAP3UNSETargs*); +extern bool_t xdr_PMAP3GETADDRargs (XDR *, PMAP3GETADDRargs*); +extern bool_t xdr_PMAP3GETADDRres (XDR *, PMAP3GETADDRres*); +extern bool_t xdr_PMAP3DUMPres (XDR *, PMAP3DUMPres*); +extern bool_t xdr_PMAP3CALLITargs (XDR *, PMAP3CALLITargs*); +extern bool_t xdr_PMAP3CALLITres (XDR *, PMAP3CALLITres*); +extern bool_t xdr_PMAP3UADDR2TADDRres (XDR *, PMAP3UADDR2TADDRres*); +extern bool_t xdr_PMAP3TADDR2UADDRargs (XDR *, PMAP3TADDR2UADDRargs*); +extern bool_t xdr_PMAP3TADDR2UADDRres (XDR *, PMAP3TADDR2UADDRres*); + + +#ifdef __cplusplus +} +#endif + +#endif /* !_PORTMAP_H_RPCGEN */ diff --git a/src/nfs/portmap.x b/src/nfs/portmap.x new file mode 100644 index 000000000..09bf556fd --- /dev/null +++ b/src/nfs/portmap.x @@ -0,0 +1,168 @@ +/* +Copyright (c) 2014, Ronnie Sahlberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +const PMAP_PORT = 111; /* portmapper port number */ + +struct pmap2_mapping { + unsigned int prog; + unsigned int vers; + unsigned int prot; + unsigned int port; +}; + +struct pmap2_call_args { + unsigned int prog; + unsigned int vers; + unsigned int proc; + opaque args<>; +}; + +struct pmap2_call_result { + unsigned int port; + opaque res<>; +}; + +struct pmap2_mapping_list { + pmap2_mapping map; + pmap2_mapping_list *next; +}; + +struct pmap2_dump_result { + struct pmap2_mapping_list *list; +}; + +struct pmap3_string_result { + string addr<>; +}; + +struct pmap3_mapping { + unsigned int prog; + unsigned int vers; + string netid<>; + string addr<>; + string owner<>; +}; + +struct pmap3_mapping_list { + pmap3_mapping map; + pmap3_mapping_list *next; +}; + +struct pmap3_dump_result { + struct pmap3_mapping_list *list; +}; + +struct pmap3_call_args { + unsigned int prog; + unsigned int vers; + unsigned int proc; + opaque args<>; +}; + +struct pmap3_call_result { + unsigned int port; + opaque res<>; +}; + +struct pmap3_netbuf { + unsigned int maxlen; + /* This pretty much contains a sockaddr_storage. + * Beware differences in endianess for ss_family + * and whether or not ss_len exists. + */ + opaque buf<>; +}; + +typedef pmap2_mapping PMAP2SETargs; +typedef pmap2_mapping PMAP2UNSETargs; +typedef pmap2_mapping PMAP2GETPORTargs; +typedef pmap2_call_args PMAP2CALLITargs; +typedef pmap2_call_result PMAP2CALLITres; +typedef pmap2_dump_result PMAP2DUMPres; + +typedef pmap3_mapping PMAP3SETargs; +typedef pmap3_mapping PMAP3UNSETargs; +typedef pmap3_mapping PMAP3GETADDRargs; +typedef pmap3_string_result PMAP3GETADDRres; +typedef pmap3_dump_result PMAP3DUMPres; +typedef pmap3_call_result PMAP3CALLITargs; +typedef pmap3_call_result PMAP3CALLITres; +typedef pmap3_netbuf PMAP3UADDR2TADDRres; +typedef pmap3_netbuf PMAP3TADDR2UADDRargs; +typedef pmap3_string_result PMAP3TADDR2UADDRres; + +program PMAP_PROGRAM { + version PMAP_V2 { + void + PMAP2_NULL(void) = 0; + + uint32_t + PMAP2_SET(PMAP2SETargs) = 1; + + uint32_t + PMAP2_UNSET(PMAP2UNSETargs) = 2; + + uint32_t + PMAP2_GETPORT(PMAP2GETPORTargs) = 3; + + PMAP2DUMPres + PMAP2_DUMP(void) = 4; + + PMAP2CALLITres + PMAP2_CALLIT(PMAP2CALLITargs) = 5; + } = 2; + version PMAP_V3 { + void + PMAP3_NULL(void) = 0; + + uint32_t + PMAP3_SET(PMAP3SETargs) = 1; + + uint32_t + PMAP3_UNSET(PMAP3UNSETargs) = 2; + + PMAP3GETADDRres + PMAP3_GETADDR(PMAP3GETADDRargs) = 3; + + PMAP3DUMPres + PMAP3_DUMP(void) = 4; + + PMAP3CALLITres + PMAP3_CALLIT(PMAP3CALLITargs) = 5; + + uint32_t + PMAP3_GETTIME(void) = 6; + + PMAP3UADDR2TADDRres + PMAP3_UADDR2TADDR(string) = 7; + + PMAP3TADDR2UADDRres + PMAP3_TADDR2UADDR(PMAP3TADDR2UADDRargs) = 8; + } = 3; +} = 100000; diff --git a/src/nfs/portmap_xdr.cpp b/src/nfs/portmap_xdr.cpp new file mode 100644 index 000000000..22d051f61 --- /dev/null +++ b/src/nfs/portmap_xdr.cpp @@ -0,0 +1,406 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "portmap.h" +#include "xdr_impl_inline.h" + +bool_t +xdr_pmap2_mapping (XDR *xdrs, pmap2_mapping *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->prot)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->port)) + return FALSE; + } else { + IXDR_PUT_U_LONG(buf, objp->prog); + IXDR_PUT_U_LONG(buf, objp->vers); + IXDR_PUT_U_LONG(buf, objp->prot); + IXDR_PUT_U_LONG(buf, objp->port); + } + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->prot)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->port)) + return FALSE; + } else { + objp->prog = IXDR_GET_U_LONG(buf); + objp->vers = IXDR_GET_U_LONG(buf); + objp->prot = IXDR_GET_U_LONG(buf); + objp->port = IXDR_GET_U_LONG(buf); + } + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->prot)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->port)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap2_call_args (XDR *xdrs, pmap2_call_args *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->prog); + IXDR_PUT_U_LONG(buf, objp->vers); + IXDR_PUT_U_LONG(buf, objp->proc); + } + if (!xdr_bytes(xdrs, &objp->args, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + + } else { + objp->prog = IXDR_GET_U_LONG(buf); + objp->vers = IXDR_GET_U_LONG(buf); + objp->proc = IXDR_GET_U_LONG(buf); + } + if (!xdr_bytes(xdrs, &objp->args, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->args, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap2_call_result (XDR *xdrs, pmap2_call_result *objp) +{ + + if (!xdr_u_int (xdrs, &objp->port)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->res, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap2_mapping_list (XDR *xdrs, pmap2_mapping_list *objp) +{ + + if (!xdr_pmap2_mapping (xdrs, &objp->map)) + return FALSE; + if (!xdr_pointer (xdrs, (char **)&objp->next, sizeof (pmap2_mapping_list), (xdrproc_t) xdr_pmap2_mapping_list)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap2_dump_result (XDR *xdrs, pmap2_dump_result *objp) +{ + + if (!xdr_pointer (xdrs, (char **)&objp->list, sizeof (pmap2_mapping_list), (xdrproc_t) xdr_pmap2_mapping_list)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap3_string_result (XDR *xdrs, pmap3_string_result *objp) +{ + + if (!xdr_string (xdrs, &objp->addr, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap3_mapping (XDR *xdrs, pmap3_mapping *objp) +{ + + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_string (xdrs, &objp->netid, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->addr, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->owner, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap3_mapping_list (XDR *xdrs, pmap3_mapping_list *objp) +{ + + if (!xdr_pmap3_mapping (xdrs, &objp->map)) + return FALSE; + if (!xdr_pointer (xdrs, (char **)&objp->next, sizeof (pmap3_mapping_list), (xdrproc_t) xdr_pmap3_mapping_list)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap3_dump_result (XDR *xdrs, pmap3_dump_result *objp) +{ + + if (!xdr_pointer (xdrs, (char **)&objp->list, sizeof (pmap3_mapping_list), (xdrproc_t) xdr_pmap3_mapping_list)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap3_call_args (XDR *xdrs, pmap3_call_args *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->prog); + IXDR_PUT_U_LONG(buf, objp->vers); + IXDR_PUT_U_LONG(buf, objp->proc); + } + if (!xdr_bytes(xdrs, &objp->args, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + + } else { + objp->prog = IXDR_GET_U_LONG(buf); + objp->vers = IXDR_GET_U_LONG(buf); + objp->proc = IXDR_GET_U_LONG(buf); + } + if (!xdr_bytes(xdrs, &objp->args, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->args, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap3_call_result (XDR *xdrs, pmap3_call_result *objp) +{ + + if (!xdr_u_int (xdrs, &objp->port)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->res, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_pmap3_netbuf (XDR *xdrs, pmap3_netbuf *objp) +{ + + if (!xdr_u_int (xdrs, &objp->maxlen)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->buf, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP2SETargs (XDR *xdrs, PMAP2SETargs *objp) +{ + + if (!xdr_pmap2_mapping (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP2UNSETargs (XDR *xdrs, PMAP2UNSETargs *objp) +{ + + if (!xdr_pmap2_mapping (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP2GETPORTargs (XDR *xdrs, PMAP2GETPORTargs *objp) +{ + + if (!xdr_pmap2_mapping (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP2CALLITargs (XDR *xdrs, PMAP2CALLITargs *objp) +{ + + if (!xdr_pmap2_call_args (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP2CALLITres (XDR *xdrs, PMAP2CALLITres *objp) +{ + + if (!xdr_pmap2_call_result (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP2DUMPres (XDR *xdrs, PMAP2DUMPres *objp) +{ + + if (!xdr_pmap2_dump_result (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3SETargs (XDR *xdrs, PMAP3SETargs *objp) +{ + + if (!xdr_pmap3_mapping (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3UNSETargs (XDR *xdrs, PMAP3UNSETargs *objp) +{ + + if (!xdr_pmap3_mapping (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3GETADDRargs (XDR *xdrs, PMAP3GETADDRargs *objp) +{ + + if (!xdr_pmap3_mapping (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3GETADDRres (XDR *xdrs, PMAP3GETADDRres *objp) +{ + + if (!xdr_pmap3_string_result (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3DUMPres (XDR *xdrs, PMAP3DUMPres *objp) +{ + + if (!xdr_pmap3_dump_result (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3CALLITargs (XDR *xdrs, PMAP3CALLITargs *objp) +{ + + if (!xdr_pmap3_call_result (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3CALLITres (XDR *xdrs, PMAP3CALLITres *objp) +{ + + if (!xdr_pmap3_call_result (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3UADDR2TADDRres (XDR *xdrs, PMAP3UADDR2TADDRres *objp) +{ + + if (!xdr_pmap3_netbuf (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3TADDR2UADDRargs (XDR *xdrs, PMAP3TADDR2UADDRargs *objp) +{ + + if (!xdr_pmap3_netbuf (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_PMAP3TADDR2UADDRres (XDR *xdrs, PMAP3TADDR2UADDRres *objp) +{ + + if (!xdr_pmap3_string_result (xdrs, objp)) + return FALSE; + return TRUE; +} diff --git a/src/nfs/rpc.h b/src/nfs/rpc.h new file mode 100644 index 000000000..bce97ddfe --- /dev/null +++ b/src/nfs/rpc.h @@ -0,0 +1,160 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _RPC_H_RPCGEN +#define _RPC_H_RPCGEN + +#include "xdr_impl.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define RPC_MSG_VERSION 2 + +enum rpc_auth_flavor { + RPC_AUTH_NONE = 0, + RPC_AUTH_SYS = 1, + RPC_AUTH_SHORT = 2, + RPC_AUTH_DH = 3, + RPC_RPCSEC_GSS = 6, +}; +typedef enum rpc_auth_flavor rpc_auth_flavor; + +enum rpc_msg_type { + RPC_CALL = 0, + RPC_REPLY = 1, +}; +typedef enum rpc_msg_type rpc_msg_type; + +enum rpc_reply_stat { + RPC_MSG_ACCEPTED = 0, + RPC_MSG_DENIED = 1, +}; +typedef enum rpc_reply_stat rpc_reply_stat; + +enum rpc_accept_stat { + RPC_SUCCESS = 0, + RPC_PROG_UNAVAIL = 1, + RPC_PROG_MISMATCH = 2, + RPC_PROC_UNAVAIL = 3, + RPC_GARBAGE_ARGS = 4, + RPC_SYSTEM_ERR = 5, +}; +typedef enum rpc_accept_stat rpc_accept_stat; + +enum rpc_reject_stat { + RPC_MISMATCH = 0, + RPC_AUTH_ERROR = 1, +}; +typedef enum rpc_reject_stat rpc_reject_stat; + +enum rpc_auth_stat { + RPC_AUTH_OK = 0, + RPC_AUTH_BADCRED = 1, + RPC_AUTH_REJECTEDCRED = 2, + RPC_AUTH_BADVERF = 3, + RPC_AUTH_REJECTEDVERF = 4, + RPC_AUTH_TOOWEAK = 5, + RPC_AUTH_INVALIDRESP = 6, + RPC_AUTH_FAILED = 7, +}; +typedef enum rpc_auth_stat rpc_auth_stat; + +struct rpc_opaque_auth { + rpc_auth_flavor flavor; + xdr_string_t body; +}; +typedef struct rpc_opaque_auth rpc_opaque_auth; + +struct rpc_call_body { + u_int rpcvers; + u_int prog; + u_int vers; + u_int proc; + rpc_opaque_auth cred; + rpc_opaque_auth verf; +}; +typedef struct rpc_call_body rpc_call_body; + +struct rpc_mismatch_info { + u_int min_version; + u_int max_version; +}; +typedef struct rpc_mismatch_info rpc_mismatch_info; + +struct rpc_accepted_reply_body { + rpc_accept_stat stat; + union { + rpc_mismatch_info mismatch_info; + }; +}; +typedef struct rpc_accepted_reply_body rpc_accepted_reply_body; + +struct rpc_accepted_reply { + rpc_opaque_auth verf; + rpc_accepted_reply_body reply_data; +}; +typedef struct rpc_accepted_reply rpc_accepted_reply; + +struct rpc_rejected_reply { + rpc_reject_stat stat; + union { + rpc_mismatch_info mismatch_info; + rpc_auth_stat auth_stat; + }; +}; +typedef struct rpc_rejected_reply rpc_rejected_reply; + +struct rpc_reply_body { + rpc_reply_stat stat; + union { + rpc_accepted_reply areply; + rpc_rejected_reply rreply; + }; +}; +typedef struct rpc_reply_body rpc_reply_body; + +struct rpc_msg_body { + rpc_msg_type dir; + union { + rpc_call_body cbody; + rpc_reply_body rbody; + }; +}; +typedef struct rpc_msg_body rpc_msg_body; + +struct rpc_msg { + u_int xid; + rpc_msg_body body; +}; +typedef struct rpc_msg rpc_msg; + +/* the xdr functions */ + + +extern bool_t xdr_rpc_auth_flavor (XDR *, rpc_auth_flavor*); +extern bool_t xdr_rpc_msg_type (XDR *, rpc_msg_type*); +extern bool_t xdr_rpc_reply_stat (XDR *, rpc_reply_stat*); +extern bool_t xdr_rpc_accept_stat (XDR *, rpc_accept_stat*); +extern bool_t xdr_rpc_reject_stat (XDR *, rpc_reject_stat*); +extern bool_t xdr_rpc_auth_stat (XDR *, rpc_auth_stat*); +extern bool_t xdr_rpc_opaque_auth (XDR *, rpc_opaque_auth*); +extern bool_t xdr_rpc_call_body (XDR *, rpc_call_body*); +extern bool_t xdr_rpc_mismatch_info (XDR *, rpc_mismatch_info*); +extern bool_t xdr_rpc_accepted_reply_body (XDR *, rpc_accepted_reply_body*); +extern bool_t xdr_rpc_accepted_reply (XDR *, rpc_accepted_reply*); +extern bool_t xdr_rpc_rejected_reply (XDR *, rpc_rejected_reply*); +extern bool_t xdr_rpc_reply_body (XDR *, rpc_reply_body*); +extern bool_t xdr_rpc_msg_body (XDR *, rpc_msg_body*); +extern bool_t xdr_rpc_msg (XDR *, rpc_msg*); + + +#ifdef __cplusplus +} +#endif + +#endif /* !_RPC_H_RPCGEN */ diff --git a/src/nfs/rpc.x b/src/nfs/rpc.x new file mode 100644 index 000000000..6f71b05bc --- /dev/null +++ b/src/nfs/rpc.x @@ -0,0 +1,113 @@ +/* Based on RFC 5531 - RPC: Remote Procedure Call Protocol Specification Version 2 */ + +const RPC_MSG_VERSION = 2; + +enum rpc_auth_flavor { + RPC_AUTH_NONE = 0, + RPC_AUTH_SYS = 1, + RPC_AUTH_SHORT = 2, + RPC_AUTH_DH = 3, + RPC_RPCSEC_GSS = 6 +}; + +enum rpc_msg_type { + RPC_CALL = 0, + RPC_REPLY = 1 +}; + +enum rpc_reply_stat { + RPC_MSG_ACCEPTED = 0, + RPC_MSG_DENIED = 1 +}; + +enum rpc_accept_stat { + RPC_SUCCESS = 0, + RPC_PROG_UNAVAIL = 1, + RPC_PROG_MISMATCH = 2, + RPC_PROC_UNAVAIL = 3, + RPC_GARBAGE_ARGS = 4, + RPC_SYSTEM_ERR = 5 +}; + +enum rpc_reject_stat { + RPC_MISMATCH = 0, + RPC_AUTH_ERROR = 1 +}; + +enum rpc_auth_stat { + RPC_AUTH_OK = 0, + /* + * failed at remote end + */ + RPC_AUTH_BADCRED = 1, /* bogus credentials (seal broken) */ + RPC_AUTH_REJECTEDCRED = 2, /* client should begin new session */ + RPC_AUTH_BADVERF = 3, /* bogus verifier (seal broken) */ + RPC_AUTH_REJECTEDVERF = 4, /* verifier expired or was replayed */ + RPC_AUTH_TOOWEAK = 5, /* rejected due to security reasons */ + /* + * failed locally + */ + RPC_AUTH_INVALIDRESP = 6, /* bogus response verifier */ + RPC_AUTH_FAILED = 7 /* some unknown reason */ +}; + +struct rpc_opaque_auth { + rpc_auth_flavor flavor; + opaque body<400>; +}; + +struct rpc_call_body { + u_int rpcvers; + u_int prog; + u_int vers; + u_int proc; + rpc_opaque_auth cred; + rpc_opaque_auth verf; + /* procedure-specific parameters start here */ +}; + +struct rpc_mismatch_info { + unsigned int min_version; + unsigned int max_version; +}; + +union rpc_accepted_reply_body switch (rpc_accept_stat stat) { +case RPC_SUCCESS: + void; + /* procedure-specific results start here */ +case RPC_PROG_MISMATCH: + rpc_mismatch_info mismatch_info; +default: + void; +}; + +struct rpc_accepted_reply { + rpc_opaque_auth verf; + rpc_accepted_reply_body reply_data; +}; + +union rpc_rejected_reply switch (rpc_reject_stat stat) { +case RPC_MISMATCH: + rpc_mismatch_info mismatch_info; +case RPC_AUTH_ERROR: + rpc_auth_stat auth_stat; +}; + +union rpc_reply_body switch (rpc_reply_stat stat) { +case RPC_MSG_ACCEPTED: + rpc_accepted_reply areply; +case RPC_MSG_DENIED: + rpc_rejected_reply rreply; +}; + +union rpc_msg_body switch (rpc_msg_type dir) { +case RPC_CALL: + rpc_call_body cbody; +case RPC_REPLY: + rpc_reply_body rbody; +}; + +struct rpc_msg { + u_int xid; + rpc_msg_body body; +}; diff --git a/src/nfs/rpc_impl.h b/src/nfs/rpc_impl.h new file mode 100644 index 000000000..4acfdf875 --- /dev/null +++ b/src/nfs/rpc_impl.h @@ -0,0 +1,43 @@ +#pragma once + +#include "rpc.h" + +struct rpc_op_t; + +// Handler should return 1 if the request is processed asynchronously +// and requires the incoming message to not be freed until processing ends, +// 0 otherwise. +typedef int (*rpc_handler_t)(void *opaque, rpc_op_t *rop); + +struct rpc_service_proc_t +{ + uint32_t prog; + uint32_t vers; + uint32_t proc; + rpc_handler_t handler_fn; + xdrproc_t req_fn; + uint32_t req_size; + xdrproc_t resp_fn; + uint32_t resp_size; + void *opaque; +}; + +inline bool operator < (const rpc_service_proc_t & a, const rpc_service_proc_t & b) +{ + return a.prog < b.prog || a.prog == b.prog && (a.vers < b.vers || a.vers == b.vers && a.proc < b.proc); +} + +struct rpc_op_t +{ + void *client; + uint8_t *buffer; + XDR *xdrs; + rpc_msg in_msg, out_msg; + void *request; + void *reply; + xdrproc_t reply_fn; + uint32_t reply_marker; + bool referenced; +}; + +void rpc_queue_reply(rpc_op_t *rop); diff --git a/src/nfs/rpc_xdr.cpp b/src/nfs/rpc_xdr.cpp new file mode 100644 index 000000000..c3bba80d5 --- /dev/null +++ b/src/nfs/rpc_xdr.cpp @@ -0,0 +1,253 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "rpc.h" +#include "xdr_impl_inline.h" + +bool_t +xdr_rpc_auth_flavor (XDR *xdrs, rpc_auth_flavor *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_msg_type (XDR *xdrs, rpc_msg_type *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_reply_stat (XDR *xdrs, rpc_reply_stat *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_accept_stat (XDR *xdrs, rpc_accept_stat *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_reject_stat (XDR *xdrs, rpc_reject_stat *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_auth_stat (XDR *xdrs, rpc_auth_stat *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_opaque_auth (XDR *xdrs, rpc_opaque_auth *objp) +{ + + if (!xdr_rpc_auth_flavor (xdrs, &objp->flavor)) + return FALSE; + if (!xdr_bytes(xdrs, &objp->body, 400)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_call_body (XDR *xdrs, rpc_call_body *objp) +{ + + + if (xdrs->x_op == XDR_ENCODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->rpcvers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->rpcvers); + IXDR_PUT_U_LONG(buf, objp->prog); + IXDR_PUT_U_LONG(buf, objp->vers); + IXDR_PUT_U_LONG(buf, objp->proc); + } + if (!xdr_rpc_opaque_auth (xdrs, &objp->cred)) + return FALSE; + if (!xdr_rpc_opaque_auth (xdrs, &objp->verf)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (1) { + if (!xdr_u_int (xdrs, &objp->rpcvers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + + } else { + objp->rpcvers = IXDR_GET_U_LONG(buf); + objp->prog = IXDR_GET_U_LONG(buf); + objp->vers = IXDR_GET_U_LONG(buf); + objp->proc = IXDR_GET_U_LONG(buf); + } + if (!xdr_rpc_opaque_auth (xdrs, &objp->cred)) + return FALSE; + if (!xdr_rpc_opaque_auth (xdrs, &objp->verf)) + return FALSE; + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->rpcvers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->proc)) + return FALSE; + if (!xdr_rpc_opaque_auth (xdrs, &objp->cred)) + return FALSE; + if (!xdr_rpc_opaque_auth (xdrs, &objp->verf)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_mismatch_info (XDR *xdrs, rpc_mismatch_info *objp) +{ + + if (!xdr_u_int (xdrs, &objp->min_version)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->max_version)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_accepted_reply_body (XDR *xdrs, rpc_accepted_reply_body *objp) +{ + + if (!xdr_rpc_accept_stat (xdrs, &objp->stat)) + return FALSE; + switch (objp->stat) { + case RPC_SUCCESS: + break; + case RPC_PROG_MISMATCH: + if (!xdr_rpc_mismatch_info (xdrs, &objp->mismatch_info)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_rpc_accepted_reply (XDR *xdrs, rpc_accepted_reply *objp) +{ + + if (!xdr_rpc_opaque_auth (xdrs, &objp->verf)) + return FALSE; + if (!xdr_rpc_accepted_reply_body (xdrs, &objp->reply_data)) + return FALSE; + return TRUE; +} + +bool_t +xdr_rpc_rejected_reply (XDR *xdrs, rpc_rejected_reply *objp) +{ + + if (!xdr_rpc_reject_stat (xdrs, &objp->stat)) + return FALSE; + switch (objp->stat) { + case RPC_MISMATCH: + if (!xdr_rpc_mismatch_info (xdrs, &objp->mismatch_info)) + return FALSE; + break; + case RPC_AUTH_ERROR: + if (!xdr_rpc_auth_stat (xdrs, &objp->auth_stat)) + return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_rpc_reply_body (XDR *xdrs, rpc_reply_body *objp) +{ + + if (!xdr_rpc_reply_stat (xdrs, &objp->stat)) + return FALSE; + switch (objp->stat) { + case RPC_MSG_ACCEPTED: + if (!xdr_rpc_accepted_reply (xdrs, &objp->areply)) + return FALSE; + break; + case RPC_MSG_DENIED: + if (!xdr_rpc_rejected_reply (xdrs, &objp->rreply)) + return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_rpc_msg_body (XDR *xdrs, rpc_msg_body *objp) +{ + + if (!xdr_rpc_msg_type (xdrs, &objp->dir)) + return FALSE; + switch (objp->dir) { + case RPC_CALL: + if (!xdr_rpc_call_body (xdrs, &objp->cbody)) + return FALSE; + break; + case RPC_REPLY: + if (!xdr_rpc_reply_body (xdrs, &objp->rbody)) + return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_rpc_msg (XDR *xdrs, rpc_msg *objp) +{ + + if (!xdr_u_int (xdrs, &objp->xid)) + return FALSE; + if (!xdr_rpc_msg_body (xdrs, &objp->body)) + return FALSE; + return TRUE; +} diff --git a/src/nfs/run-rpcgen.sh b/src/nfs/run-rpcgen.sh new file mode 100755 index 000000000..9224d174d --- /dev/null +++ b/src/nfs/run-rpcgen.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -e + +# 1) remove all extern non-xdr functions (service, client) +# 2) use xdr_string_t for strings instead of char* +# 3) remove K&R #ifdefs +# 4) remove register int32_t* buf +# 5) remove union names +# 6) use xdr_string_t for opaques instead of u_int + char* +# 7) TODO: generate normal procedure stubs +run_rpcgen() { + rpcgen -h $1.x | \ + perl -e ' + { local $/ = undef; $_ = <>; } + s/^extern(?!.*"C"|.*bool_t xdr.*XDR).*\n//gm; + s/#include /#include "xdr_impl.h"/; + s/^typedef char \*/typedef xdr_string_t /gm; + s/^(\s*)char \*(?!.*_val)/$1xdr_string_t /gm; + # remove union names + s/ \w+_u;/;/gs; + # use xdr_string_t for opaques + s/struct\s*\{\s*u_int\s+\w+_len;\s*char\s+\*\w+_val;\s*\}\s*/xdr_string_t /gs; + # remove stdc/k&r + s/^#if.*__STDC__.*//gm; + s/\n#else[^\n]*K&R.*?\n#endif[^\n]*K&R[^\n]*//gs; + print;' > $1.h + rpcgen -c $1.x | \ + perl -pe ' + s/register int32_t \*buf;\s*//g; + s/\bbuf\s*=[^;]+;\s*//g; + s/\bbuf\s*==\s*NULL/1/g; + # remove union names + s/(\.|->)\w+_u\./$1/g; + # use xdr_string_t for opaques + # xdr_bytes(xdrs, (char**)&objp->data.data_val, (char**)&objp->data.data_len, 400) + # -> xdr_bytes(xdrs, &objp->data, 400) + # xdr_bytes(xdrs, (char**)&objp->data_val, (char**)&objp->data_len, 400) + # -> xdr_bytes(xdrs, objp, 400) + s/xdr_bytes\s*\(\s*xdrs,\s*\(\s*char\s*\*\*\s*\)\s*([^()]+?)\.\w+_val\s*,\s*\(\s*u_int\s*\*\s*\)\s*\1\.\w+_len,/xdr_bytes(xdrs, $1,/gs; + s/xdr_bytes\s*\(\s*xdrs,\s*\(\s*char\s*\*\*\s*\)\s*&\s*([^()]+?)->\w+_val\s*,\s*\(\s*u_int\s*\*\s*\)\s*&\s*\1->\w+_len,/xdr_bytes(xdrs, $1,/gs; + # add include + if (/#include/) { $_ .= "#include \"xdr_impl_inline.h\"\n"; }' > ${1}_xdr.cpp +} + +run_rpcgen nfs +run_rpcgen rpc +run_rpcgen portmap diff --git a/src/nfs/xdr_impl.cpp b/src/nfs/xdr_impl.cpp new file mode 100644 index 000000000..1c2648981 --- /dev/null +++ b/src/nfs/xdr_impl.cpp @@ -0,0 +1,107 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) +// +// Efficient XDR implementation almost compatible with rpcgen (see run-rpcgen.sh) + +#include "xdr_impl_inline.h" + +XDR* xdr_create() +{ + return new XDR; +} + +void xdr_destroy(XDR* xdrs) +{ + xdr_reset(xdrs); + delete xdrs; +} + +void xdr_reset(XDR *xdrs) +{ + for (auto buf: xdrs->allocs) + { + free(buf); + } + xdrs->buf = NULL; + xdrs->avail = 0; + xdrs->allocs.resize(0); + xdrs->in_linked_list.resize(0); + xdrs->cur_out.resize(0); + xdrs->last_end = 0; + xdrs->buf_list.resize(0); +} + +int xdr_decode(XDR *xdrs, void *buf, unsigned size, xdrproc_t fn, void *data) +{ + xdrs->x_op = XDR_DECODE; + xdrs->buf = (uint8_t*)buf; + xdrs->avail = size; + return fn(xdrs, data); +} + +int xdr_encode(XDR *xdrs, xdrproc_t fn, void *data) +{ + xdrs->x_op = XDR_ENCODE; + return fn(xdrs, data); +} + +void xdr_encode_finish(XDR *xdrs, iovec **iov_list, unsigned *iov_count) +{ + if (xdrs->last_end < xdrs->cur_out.size()) + { + xdrs->buf_list.push_back((iovec){ + .iov_base = 0, + .iov_len = xdrs->cur_out.size() - xdrs->last_end, + }); + xdrs->last_end = xdrs->cur_out.size(); + } + uint8_t *cur_buf = xdrs->cur_out.data(); + for (auto & buf: xdrs->buf_list) + { + if (!buf.iov_base) + { + buf.iov_base = cur_buf; + cur_buf += buf.iov_len; + } + } + *iov_list = xdrs->buf_list.data(); + *iov_count = xdrs->buf_list.size(); +} + +void xdr_dump_encoded(XDR *xdrs) +{ + for (auto & buf: xdrs->buf_list) + { + for (int i = 0; i < buf.iov_len; i++) + printf("%02x", ((uint8_t*)buf.iov_base)[i]); + } + printf("\n"); +} + +void xdr_add_malloc(XDR *xdrs, void *buf) +{ + xdrs->allocs.push_back(buf); +} + +xdr_string_t xdr_copy_string(XDR *xdrs, const std::string & str) +{ + char *cp = (char*)malloc_or_die(str.size()+1); + memcpy(cp, str.data(), str.size()); + cp[str.size()] = 0; + xdr_add_malloc(xdrs, cp); + return (xdr_string_t){ str.size(), cp }; +} + +xdr_string_t xdr_copy_string(XDR *xdrs, const char *str) +{ + return xdr_copy_string(xdrs, str, strlen(str)); +} + +xdr_string_t xdr_copy_string(XDR *xdrs, const char *str, size_t len) +{ + char *cp = (char*)malloc_or_die(len+1); + memcpy(cp, str, len); + cp[len] = 0; + xdr_add_malloc(xdrs, cp); + return (xdr_string_t){ len, cp }; +} diff --git a/src/nfs/xdr_impl.h b/src/nfs/xdr_impl.h new file mode 100644 index 000000000..badfe75ff --- /dev/null +++ b/src/nfs/xdr_impl.h @@ -0,0 +1,83 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) +// +// Efficient XDR implementation almost compatible with rpcgen (see run-rpcgen.sh) + +#pragma once + +#include +#include +#include + +#define XDR_COPY_LENGTH 128 + +struct xdr_string_t +{ + size_t size; + char *data; + + operator std::string() + { + return std::string(data, size); + } + + bool operator == (const char *str) + { + if (!str) + return false; + int i; + for (i = 0; i < size; i++) + if (!str[i] || str[i] != data[i]) + return false; + if (str[i]) + return false; + return true; + } + + bool operator != (const char *str) + { + return !(*this == str); + } +}; + +typedef uint32_t u_int; +typedef uint32_t enum_t; +typedef uint32_t bool_t; +struct XDR; +typedef int (*xdrproc_t)(XDR *xdrs, void *data); + +// Create an empty XDR object +XDR* xdr_create(); + +// Destroy the XDR object +void xdr_destroy(XDR* xdrs); + +// Free resources from any previous xdr_decode/xdr_encode calls +void xdr_reset(XDR *xdrs); + +// Try to decode bytes from buffer using +// Result may contain memory allocations that will be valid until the next call to xdr_{reset,destroy,decode,encode} +int xdr_decode(XDR *xdrs, void *buf, unsigned size, xdrproc_t fn, void *data); + +// Try to encode using +// May be mixed with xdr_decode +// May be called multiple times to encode multiple parts of the same message +int xdr_encode(XDR *xdrs, xdrproc_t fn, void *data); + +// Get the result of previous xdr_encodes as a list of 's +// in (start) and (count). +// The resulting iov_list is valid until the next call to xdr_{reset,destroy}. +// It may contain references to the original data, so original data must not +// be freed until the result is fully processed (sent). +void xdr_encode_finish(XDR *xdrs, iovec **iov_list, unsigned *iov_count); + +// Remember an allocated buffer to free it later on xdr_reset() or xdr_destroy() +void xdr_add_malloc(XDR *xdrs, void *buf); + +xdr_string_t xdr_copy_string(XDR *xdrs, const std::string & str); + +xdr_string_t xdr_copy_string(XDR *xdrs, const char *str); + +xdr_string_t xdr_copy_string(XDR *xdrs, const char *str, size_t len); + +void xdr_dump_encoded(XDR *xdrs); diff --git a/src/nfs/xdr_impl_inline.h b/src/nfs/xdr_impl_inline.h new file mode 100644 index 000000000..bcb2105ff --- /dev/null +++ b/src/nfs/xdr_impl_inline.h @@ -0,0 +1,309 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) +// +// Efficient XDR implementation almost compatible with rpcgen (see run-rpcgen.sh) + +// XDR in a nutshell: +// +// int: big endian 32bit +// unsigned: BE 32bit +// enum: BE 32bit +// bool: BE 32bit 0/1 +// hyper: BE 64bit +// unsigned hyper: BE 64bit +// float: BE float +// double: BE double +// quadruple: BE long double +// opaque[n] (fixed-length): bytes, padded to !(n%4) +// opaque (variable-length): BE 32bit length, then n bytes, padded to !(n%4) +// string: same as opaque +// array[n] (fixed-length): n items of type T +// vector (variable-length): BE 32bit length, then n items of type T +// struct: components in the same order as specified +// union: BE 32bit variant id, then variant of the union +// void: nothing (empty, 0 byte data) +// optional (XDR T*): BE 32bit 1/0, then T or nothing +// linked list: sequence of optional entries +// +// RPC over TCP: +// +// BE 32bit length, then rpc_msg, then the procedure message itself + +#pragma once + +#include "xdr_impl.h" + +#include +#include +#include + +#include "../malloc_or_die.h" + +#define FALSE 0 +#define TRUE 1 +#define XDR_ENCODE 0 +#define XDR_DECODE 1 +#define BYTES_PER_XDR_UNIT 4 +#define IXDR_PUT_U_LONG(a, b) +#define IXDR_GET_U_LONG(a) 0 +#define IXDR_PUT_BOOL(a, b) +#define IXDR_GET_BOOL(a) 0 +#define XDR_INLINE(xdrs, len) NULL + +struct xdr_linked_list_t +{ + xdrproc_t fn; + unsigned entry_size, size, cap; + void *base; + unsigned has_next, link_offset; +}; + +struct XDR +{ + int x_op; + + // For decoding: + uint8_t *buf = NULL; + unsigned avail = 0; + std::vector allocs; + std::vector in_linked_list; + + // For encoding: + std::vector cur_out; + unsigned last_end = 0; + std::vector buf_list; +}; + +uint32_t inline len_pad4(uint32_t len) +{ + return ((len+3)/4) * 4; +} + +inline int xdr_opaque(XDR *xdrs, void *data, uint32_t len) +{ + if (len <= 0) + { + return 1; + } + if (xdrs->x_op == XDR_DECODE) + { + uint32_t padded = len_pad4(len); + if (xdrs->avail < padded) + return 0; + memcpy(data, xdrs->buf, len); + xdrs->buf += padded; + xdrs->avail -= padded; + } + else + { + unsigned old = xdrs->cur_out.size(); + uint32_t pad = (len & 3) ? (4 - (len & 3)) : 0; + xdrs->cur_out.resize(old + len + pad); + memcpy(xdrs->cur_out.data()+old, data, len); + for (uint32_t i = 0; i < pad; i++) + xdrs->cur_out[old+i] = 0; + } + return 1; +} + +inline int xdr_bytes(XDR *xdrs, xdr_string_t *data, uint32_t maxlen) +{ + if (xdrs->x_op == XDR_DECODE) + { + if (xdrs->avail < 4) + return 0; + uint32_t len = be32toh(*((uint32_t*)xdrs->buf)); + uint32_t padded = len_pad4(len); + if (xdrs->avail < 4+padded) + return 0; + data->size = len; + data->data = (char*)(xdrs->buf+4); + xdrs->buf += 4+padded; + xdrs->avail -= 4+padded; + } + else + { + if (data->size < XDR_COPY_LENGTH) + { + unsigned old = xdrs->cur_out.size(); + xdrs->cur_out.resize(old + 4+data->size); + *(uint32_t*)(xdrs->cur_out.data() + old) = htobe32(data->size); + memcpy(xdrs->cur_out.data()+old+4, data->data, data->size); + } + else + { + unsigned old = xdrs->cur_out.size(); + xdrs->cur_out.resize(old + 4); + *(uint32_t*)(xdrs->cur_out.data() + old) = htobe32(data->size); + xdrs->buf_list.push_back((iovec){ + .iov_base = 0, + .iov_len = xdrs->cur_out.size() - xdrs->last_end, + }); + xdrs->last_end = xdrs->cur_out.size(); + xdrs->buf_list.push_back((iovec) + { + .iov_base = (void*)data->data, + .iov_len = data->size, + }); + } + if (data->size & 3) + { + int pad = 4-(data->size & 3); + unsigned old = xdrs->cur_out.size(); + xdrs->cur_out.resize(old+pad); + for (int i = 0; i < pad; i++) + xdrs->cur_out[old+i] = 0; + } + } + return 1; +} + +inline int xdr_string(XDR *xdrs, xdr_string_t *data, uint32_t maxlen) +{ + return xdr_bytes(xdrs, data, maxlen); +} + +inline int xdr_u_int(XDR *xdrs, void *data) +{ + if (xdrs->x_op == XDR_DECODE) + { + if (xdrs->avail < 4) + return 0; + *((uint32_t*)data) = be32toh(*((uint32_t*)xdrs->buf)); + xdrs->buf += 4; + xdrs->avail -= 4; + } + else + { + unsigned old = xdrs->cur_out.size(); + xdrs->cur_out.resize(old + 4); + *(uint32_t*)(xdrs->cur_out.data() + old) = htobe32(*(uint32_t*)data); + } + return 1; +} + +inline int xdr_enum(XDR *xdrs, void *data) +{ + return xdr_u_int(xdrs, data); +} + +inline int xdr_bool(XDR *xdrs, void *data) +{ + return xdr_u_int(xdrs, data); +} + +inline int xdr_uint64_t(XDR *xdrs, void *data) +{ + if (xdrs->x_op == XDR_DECODE) + { + if (xdrs->avail < 8) + return 0; + *((uint64_t*)data) = be64toh(*((uint64_t*)xdrs->buf)); + xdrs->buf += 8; + xdrs->avail -= 8; + } + else + { + unsigned old = xdrs->cur_out.size(); + xdrs->cur_out.resize(old + 8); + *(uint64_t*)(xdrs->cur_out.data() + old) = htobe64(*(uint64_t*)data); + } + return 1; +} + +// Parse inconvenient shitty linked lists as arrays +inline int xdr_pointer(XDR *xdrs, char **data, unsigned entry_size, xdrproc_t entry_fn) +{ + if (xdrs->x_op == XDR_DECODE) + { + if (xdrs->avail < 4) + return 0; + uint32_t has_next = be32toh(*((uint32_t*)xdrs->buf)); + xdrs->buf += 4; + xdrs->avail -= 4; + *data = NULL; + if (!xdrs->in_linked_list.size() || + xdrs->in_linked_list.back().fn != entry_fn) + { + if (has_next) + { + unsigned cap = 2; + void *base = malloc_or_die(entry_size * cap); + xdrs->in_linked_list.push_back((xdr_linked_list_t){ + .fn = entry_fn, + .entry_size = entry_size, + .size = 1, + .cap = cap, + .base = base, + .has_next = 0, + .link_offset = 0, + }); + *data = (char*)base; + if (!entry_fn(xdrs, base)) + return 0; + auto & ll = xdrs->in_linked_list.back(); + while (ll.has_next) + { + ll.has_next = 0; + if (ll.size >= ll.cap) + { + ll.cap *= 2; + ll.base = realloc_or_die(ll.base, ll.entry_size * ll.cap); + } + if (!entry_fn(xdrs, (uint8_t*)ll.base + ll.entry_size*ll.size)) + return 0; + ll.size++; + } + for (unsigned i = 0; i < ll.size-1; i++) + { + *(void**)((uint8_t*)ll.base + i*ll.entry_size + ll.link_offset) = + (uint8_t*)ll.base + (i+1)*ll.entry_size; + } + xdrs->allocs.push_back(ll.base); + xdrs->in_linked_list.pop_back(); + } + } + else + { + auto & ll = xdrs->in_linked_list.back(); + xdrs->in_linked_list.back().has_next = has_next; + xdrs->in_linked_list.back().link_offset = (uint8_t*)data - (uint8_t*)ll.base - ll.entry_size*ll.size; + } + } + else + { + unsigned old = xdrs->cur_out.size(); + xdrs->cur_out.resize(old + 4); + *(uint32_t*)(xdrs->cur_out.data() + old) = htobe32(*data ? 1 : 0); + if (*data) + entry_fn(xdrs, *data); + } + return 1; +} + +inline int xdr_array(XDR *xdrs, char **data, uint32_t* len, uint32_t maxlen, uint32_t entry_size, xdrproc_t fn) +{ + if (xdrs->x_op == XDR_DECODE) + { + if (xdrs->avail < 4) + return 0; + *len = be32toh(*((uint32_t*)xdrs->buf)); + if (*len > maxlen) + return 0; + xdrs->buf += 4; + xdrs->avail -= 4; + *data = (char*)malloc_or_die(entry_size * (*len)); + for (uint32_t i = 0; i < *len; i++) + fn(xdrs, *data + entry_size*i); + xdrs->allocs.push_back(*data); + } + else + { + unsigned old = xdrs->cur_out.size(); + xdrs->cur_out.resize(old + 4); + *(uint32_t*)(xdrs->cur_out.data() + old) = htobe32(*len); + for (uint32_t i = 0; i < *len; i++) + fn(xdrs, *data + entry_size*i); + } + return 1; +} diff --git a/src/nfs_conn.cpp b/src/nfs_conn.cpp new file mode 100644 index 000000000..5418f6bfb --- /dev/null +++ b/src/nfs_conn.cpp @@ -0,0 +1,1297 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) +// +// NFS connection handler for NFS proxy + +#include + +#include "base64.h" + +#include "nfs_proxy.h" + +#include "nfs/nfs.h" + +#include "cli.h" + +#define TRUE 1 +#define FALSE 0 + +#define MAX_REQUEST_SIZE 128*1024*1024 + +static unsigned len_pad4(unsigned len) +{ + return len + (len&3 ? 4-(len&3) : 0); +} + +static std::string get_inode_name(nfs_client_t *self, diropargs3 & what) +{ + // Get name + std::string dirhash = what.dir; + std::string dir; + if (dirhash != "roothandle") + { + auto dir_it = self->parent->dir_by_hash.find(dirhash); + if (dir_it != self->parent->dir_by_hash.end()) + dir = dir_it->second; + else + return ""; + } + std::string name = what.name; + return (dir.size() + ? dir+"/"+name + : self->parent->name_prefix+name); +} + +static nfsstat3 vitastor_nfs_map_err(int err) +{ + return (err == EINVAL ? NFS3ERR_INVAL + : (err == ENOENT ? NFS3ERR_NOENT + : (err == ENOSPC ? NFS3ERR_NOSPC + : (err == EEXIST ? NFS3ERR_EXIST + : (err == EIO ? NFS3ERR_IO : (err ? NFS3ERR_IO : NFS3_OK)))))); +} + +static int nfs3_null_proc(void *opaque, rpc_op_t *rop) +{ + rpc_queue_reply(rop); + return 0; +} + +static fattr3 get_dir_attributes(nfs_client_t *self, std::string dir) +{ + auto & dinf = self->parent->dir_info.at(dir); + return (fattr3){ + .type = NF3DIR, + .mode = 0755, + .nlink = 1, + .uid = 0, + .gid = 0, + .size = 4096, + .used = 4096, + .rdev = (specdata3){ 0 }, + .fsid = self->parent->fsid, + .fileid = dinf.id, + .atime = (nfstime3){ .seconds = (u_int)dinf.mtime.tv_sec, .nseconds = (u_int)dinf.mtime.tv_nsec }, + .mtime = (nfstime3){ .seconds = (u_int)dinf.mtime.tv_sec, .nseconds = (u_int)dinf.mtime.tv_nsec }, + .ctime = (nfstime3){ .seconds = (u_int)dinf.mtime.tv_sec, .nseconds = (u_int)dinf.mtime.tv_nsec }, + }; +} + +static fattr3 get_file_attributes(nfs_client_t *self, inode_t inode_num) +{ + auto & inode_cfg = self->parent->cli->st_cli.inode_config.at(inode_num); + uint64_t used = 0; + auto st_it = self->parent->inode_stats.find(inode_num); + if (st_it != self->parent->inode_stats.end()) + { + used = st_it->second["raw_used"].uint64_value(); + auto pst_it = self->parent->pool_stats.find(INODE_POOL(inode_num)); + if (pst_it != self->parent->pool_stats.end()) + { + used /= pst_it->second["raw_to_usable"].number_value(); + } + } + return (fattr3){ + .type = NF3REG, + .mode = 0644, + .nlink = 1, + .uid = 0, + .gid = 0, + .size = inode_cfg.size, + .used = used, + .rdev = (specdata3){ 0 }, + .fsid = self->parent->fsid, + .fileid = inode_num, + //.atime = (nfstime3){ .seconds = now.tv_sec, .nseconds = now.tv_nsec }, + //.mtime = (nfstime3){ .seconds = now.tv_sec, .nseconds = now.tv_nsec }, + //.ctime = (nfstime3){ .seconds = now.tv_sec, .nseconds = now.tv_nsec }, + }; +} + +static int nfs3_getattr_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + GETATTR3args *args = (GETATTR3args*)rop->request; + GETATTR3res *reply = (GETATTR3res*)rop->reply; + bool is_dir = false; + std::string dirhash = args->object; + std::string dir; + if (args->object == "roothandle") + is_dir = true; + else + { + auto dir_it = self->parent->dir_by_hash.find(dirhash); + if (dir_it != self->parent->dir_by_hash.end()) + { + is_dir = true; + dir = dir_it->second; + } + } + if (is_dir) + { + // Directory info + *reply = (GETATTR3res){ + .status = NFS3_OK, + .resok = (GETATTR3resok){ + .obj_attributes = get_dir_attributes(self, dir), + }, + }; + } + else + { + uint64_t inode_num; + auto inode_num_it = self->parent->inode_by_hash.find(dirhash); + if (inode_num_it != self->parent->inode_by_hash.end()) + inode_num = inode_num_it->second; + auto inode_it = self->parent->cli->st_cli.inode_config.find(inode_num); + if (inode_num && inode_it != self->parent->cli->st_cli.inode_config.end()) + { + // File info + auto & inode_cfg = inode_it->second; + *reply = (GETATTR3res){ + .status = NFS3_OK, + .resok = (GETATTR3resok){ + .obj_attributes = { + .type = NF3REG, + .mode = 0644, + .nlink = 1, + .uid = 0, + .gid = 0, + .size = inode_cfg.size, + .used = inode_cfg.size, + .rdev = (specdata3){ 0 }, + .fsid = self->parent->fsid, + .fileid = inode_it->first, + //.atime = (nfstime3){ .seconds = now.tv_sec, .nseconds = now.tv_nsec }, + //.mtime = (nfstime3){ .seconds = now.tv_sec, .nseconds = now.tv_nsec }, + //.ctime = (nfstime3){ .seconds = now.tv_sec, .nseconds = now.tv_nsec }, + }, + }, + }; + } + else + { + // File not exists + *reply = (GETATTR3res){ .status = NFS3ERR_NOENT }; + } + } + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_setattr_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + SETATTR3args *args = (SETATTR3args*)rop->request; + SETATTR3res *reply = (SETATTR3res*)rop->reply; + std::string handle = args->object; + auto ino_it = self->parent->inode_by_hash.find(handle); + if (ino_it == self->parent->inode_by_hash.end()) + { + if (handle == "roothandle" || self->parent->dir_by_hash.find(handle) != self->parent->dir_by_hash.end()) + { + *reply = (SETATTR3res){ .status = NFS3ERR_ISDIR }; + } + else + { + *reply = (SETATTR3res){ .status = NFS3ERR_NOENT }; + } + rpc_queue_reply(rop); + return 0; + } + if (args->new_attributes.size.set_it) + { + auto & inode_cfg = self->parent->cli->st_cli.inode_config.at(ino_it->second); + self->parent->cmd->loop_and_wait(self->parent->cmd->start_modify(json11::Json::object { + { "image", inode_cfg.name }, + { "resize", (uint64_t)args->new_attributes.size.size }, + { "force_size", true }, + }), [self, rop](const cli_result_t & r) + { + SETATTR3res *reply = (SETATTR3res*)rop->reply; + *reply = (SETATTR3res){ .status = vitastor_nfs_map_err(r.err) }; + rpc_queue_reply(rop); + }); + return 1; + } + // Silently ignore mode, uid, gid, atime, mtime changes + *reply = (SETATTR3res){ .status = NFS3_OK }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_lookup_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + LOOKUP3args *args = (LOOKUP3args*)rop->request; + LOOKUP3res *reply = (LOOKUP3res*)rop->reply; + std::string full_name = get_inode_name(self, args->what); + if (full_name != "") + { + std::string fh = "S"+base64_encode(sha256(full_name)); + for (auto & ic: self->parent->cli->st_cli.inode_config) + { + if (ic.second.name == full_name) + { + *reply = (LOOKUP3res){ + .status = NFS3_OK, + .resok = (LOOKUP3resok){ + .object = xdr_copy_string(rop->xdrs, fh), + .obj_attributes = { + .attributes_follow = 1, + .attributes = get_file_attributes(self, ic.first), + }, + }, + }; + rpc_queue_reply(rop); + return 0; + } + } + auto dir_it = self->parent->dir_info.find(full_name); + if (dir_it != self->parent->dir_info.end()) + { + *reply = (LOOKUP3res){ + .status = NFS3_OK, + .resok = (LOOKUP3resok){ + .object = xdr_copy_string(rop->xdrs, fh), + .obj_attributes = { + .attributes_follow = 1, + .attributes = get_dir_attributes(self, full_name), + }, + }, + }; + rpc_queue_reply(rop); + return 0; + } + } + *reply = (LOOKUP3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_access_proc(void *opaque, rpc_op_t *rop) +{ + //nfs_client_t *self = (nfs_client_t*)opaque; + ACCESS3args *args = (ACCESS3args*)rop->request; + ACCESS3res *reply = (ACCESS3res*)rop->reply; + *reply = (ACCESS3res){ + .status = NFS3_OK, + .resok = (ACCESS3resok){ + .access = args->access, + }, + }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_readlink_proc(void *opaque, rpc_op_t *rop) +{ + //nfs_client_t *self = (nfs_client_t*)opaque; + //READLINK3args *args = (READLINK3args*)rop->request; + READLINK3res *reply = (READLINK3res*)rop->reply; + // Not supported yet + *reply = (READLINK3res){ .status = NFS3ERR_NOTSUPP }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_read_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + READ3args *args = (READ3args*)rop->request; + READ3res *reply = (READ3res*)rop->reply; + std::string handle = args->file; + auto ino_it = self->parent->inode_by_hash.find(handle); + if (ino_it == self->parent->inode_by_hash.end()) + { + *reply = (READ3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + if (args->count > MAX_REQUEST_SIZE) + { + *reply = (READ3res){ .status = NFS3ERR_INVAL }; + rpc_queue_reply(rop); + return 0; + } + uint64_t alignment = self->parent->cli->get_bs_bitmap_granularity(); + uint64_t aligned_offset = args->offset - (args->offset % alignment); + uint64_t aligned_count = args->offset + args->count; + if (aligned_count % alignment) + aligned_count = aligned_count + alignment - (aligned_count % alignment); + aligned_count -= aligned_offset; + void *buf = malloc_or_die(aligned_count); + xdr_add_malloc(rop->xdrs, buf); + cluster_op_t *op = new cluster_op_t; + op->opcode = OSD_OP_READ; + op->inode = ino_it->second; + op->offset = aligned_offset; + op->len = aligned_count; + op->iov.push_back(buf, aligned_count); + *reply = (READ3res){ .status = NFS3_OK }; + reply->resok.data.data = (char*)buf + args->offset - aligned_offset; + reply->resok.data.size = args->count; + op->callback = [rop](cluster_op_t *op) + { + READ3res *reply = (READ3res*)rop->reply; + if (op->retval != op->len) + { + *reply = (READ3res){ .status = vitastor_nfs_map_err(-op->retval) }; + } + else + { + auto & reply_ok = reply->resok; + // reply_ok.data.data is already set above + reply_ok.count = reply_ok.data.size; + reply_ok.eof = 0; + } + rpc_queue_reply(rop); + delete op; + }; + self->parent->cli->execute(op); + return 1; +} + +static void nfs_resize_write(nfs_client_t *self, rpc_op_t *rop, uint64_t inode, uint64_t new_size, uint64_t offset, uint64_t count, void *buf); +static void nfs_do_write(nfs_client_t *self, rpc_op_t *rop, uint64_t inode, uint64_t offset, uint64_t count, void *buf); + +static int nfs3_write_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + WRITE3args *args = (WRITE3args*)rop->request; + WRITE3res *reply = (WRITE3res*)rop->reply; + std::string handle = args->file; + auto ino_it = self->parent->inode_by_hash.find(handle); + if (ino_it == self->parent->inode_by_hash.end()) + { + *reply = (WRITE3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + if (args->count > MAX_REQUEST_SIZE) + { + *reply = (WRITE3res){ .status = NFS3ERR_INVAL }; + rpc_queue_reply(rop); + return 0; + } + uint64_t count = args->count > args->data.size ? args->data.size : args->count; + uint64_t alignment = self->parent->cli->get_bs_bitmap_granularity(); + // Pre-fill reply + *reply = (WRITE3res){ + .status = NFS3_OK, + .resok = (WRITE3resok){ + //.file_wcc = ..., + .count = (unsigned)count, + .committed = args->stable, + }, + }; + if ((args->offset % alignment) != 0 || (count % alignment) != 0) + { + // Unaligned write, requires read-modify-write + uint64_t aligned_offset = args->offset - (args->offset % alignment); + uint64_t aligned_count = args->offset + args->count; + if (aligned_count % alignment) + aligned_count = aligned_count + alignment - (aligned_count % alignment); + aligned_count -= aligned_offset; + void *buf = malloc_or_die(aligned_count); + xdr_add_malloc(rop->xdrs, buf); + // Read + cluster_op_t *op = new cluster_op_t; + op->opcode = OSD_OP_READ; + op->inode = ino_it->second; + op->offset = aligned_offset; + op->len = aligned_count; + op->iov.push_back(buf, aligned_count); + op->callback = [self, rop, count](cluster_op_t *op) + { + if (op->retval != op->len) + { + WRITE3res *reply = (WRITE3res*)rop->reply; + *reply = (WRITE3res){ .status = vitastor_nfs_map_err(-op->retval) }; + rpc_queue_reply(rop); + return; + } + void *buf = op->iov.buf[0].iov_base; + WRITE3args *args = (WRITE3args*)rop->request; + memcpy((uint8_t*)buf + args->offset - op->offset, args->data.data, count); + nfs_resize_write(self, rop, op->inode, args->offset+count, op->offset, op->len, buf); + delete op; + }; + self->parent->cli->execute(op); + } + else + { + nfs_resize_write(self, rop, ino_it->second, args->offset+count, args->offset, count, args->data.data); + } + return 1; +} + +static void nfs_resize_write(nfs_client_t *self, rpc_op_t *rop, uint64_t inode, uint64_t new_size, uint64_t offset, uint64_t count, void *buf) +{ + // Check if we have to resize the inode before writing + auto inode_it = self->parent->cli->st_cli.inode_config.find(inode); + if (inode_it != self->parent->cli->st_cli.inode_config.end() && + inode_it->second.size < new_size) + { + self->parent->cmd->loop_and_wait(self->parent->cmd->start_modify(json11::Json::object { + { "image", inode_it->second.name }, + { "resize", new_size }, + { "force_size", true }, + }), [=](const cli_result_t & r) + { + if (r.err) + { + if (r.err == EAGAIN) + { + // Multiple concurrent resize requests received, try to repeat + nfs_resize_write(self, rop, inode, new_size, offset, count, buf); + return; + } + WRITE3res *reply = (WRITE3res*)rop->reply; + *reply = (WRITE3res){ .status = vitastor_nfs_map_err(r.err) }; + rpc_queue_reply(rop); + return; + } + nfs_do_write(self, rop, inode, offset, count, buf); + }); + } + else + { + nfs_do_write(self, rop, inode, offset, count, buf); + } +} + +static void nfs_do_write(nfs_client_t *self, rpc_op_t *rop, uint64_t inode, uint64_t offset, uint64_t count, void *buf) +{ + cluster_op_t *op = new cluster_op_t; + op->opcode = OSD_OP_WRITE; + op->inode = inode; + op->offset = offset; + op->len = count; + op->iov.push_back(buf, count); + op->callback = [self, rop](cluster_op_t *op) + { + WRITE3args *args = (WRITE3args*)rop->request; + WRITE3res *reply = (WRITE3res*)rop->reply; + if (op->retval != op->len) + { + *reply = (WRITE3res){ .status = vitastor_nfs_map_err(-op->retval) }; + delete op; + rpc_queue_reply(rop); + } + else + { + *(uint64_t*)reply->resok.verf = self->parent->server_id; + delete op; + if (!self->parent->cli->get_immediate_commit() && + args->stable != UNSTABLE) + { + // Client requested a stable write. Add an fsync + op = new cluster_op_t; + op->opcode = OSD_OP_SYNC; + op->callback = [rop](cluster_op_t *op) + { + if (op->retval != 0) + { + WRITE3res *reply = (WRITE3res*)rop->reply; + *reply = (WRITE3res){ .status = vitastor_nfs_map_err(-op->retval) }; + } + delete op; + rpc_queue_reply(rop); + }; + self->parent->cli->execute(op); + } + else + { + rpc_queue_reply(rop); + } + } + }; + self->parent->cli->execute(op); +} + +static int nfs3_create_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + CREATE3args *args = (CREATE3args*)rop->request; + CREATE3res *reply = (CREATE3res*)rop->reply; + std::string full_name = get_inode_name(self, args->where); + if (full_name == "") + { + *reply = (CREATE3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + // Run create command + self->parent->cmd->loop_and_wait(self->parent->cmd->start_create(json11::Json::object { + { "image", full_name }, + { "pool", self->parent->default_pool }, + { "size", args->how.mode == NFS_EXCLUSIVE || !args->how.obj_attributes.size.set_it ? 0 : args->how.obj_attributes.size.size }, + { "force_size", true }, + }), [self, rop, full_name](const cli_result_t & r) + { + if (r.err) + fprintf(stderr, "create(%s) failed: %s (code %d)\n", full_name.c_str(), r.text.c_str(), r.err); + CREATE3res *reply = (CREATE3res*)rop->reply; + *reply = (CREATE3res){ .status = vitastor_nfs_map_err(r.err) }; + if (!r.err) + { + auto inode_num = self->parent->cli->st_cli.inode_by_name.at(full_name); + reply->resok = (CREATE3resok){ + .obj = { + .handle_follows = 1, + .handle = xdr_copy_string(rop->xdrs, "S"+base64_encode(sha256(full_name))), + }, + .obj_attributes = { + .attributes_follow = 1, + .attributes = get_file_attributes(self, inode_num), + }, + .dir_wcc = { + .before = { + .attributes_follow = 0, + }, + .after = { + .attributes_follow = 0, + }, + }, + }; + } + rpc_queue_reply(rop); + }); + return 1; +} + +static int nfs3_mkdir_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + MKDIR3args *args = (MKDIR3args*)rop->request; + MKDIR3res *reply = (MKDIR3res*)rop->reply; + std::string full_name = get_inode_name(self, args->where); + if (full_name == "") + { + *reply = (MKDIR3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + auto inode_it = self->parent->cli->st_cli.inode_by_name.find(full_name); + if (inode_it != self->parent->cli->st_cli.inode_by_name.end()) + { + *reply = (MKDIR3res){ .status = NFS3ERR_EXIST }; + rpc_queue_reply(rop); + return 0; + } + auto dir_id_it = self->parent->dir_info.find(full_name); + if (dir_id_it != self->parent->dir_info.end()) + { + *reply = (MKDIR3res){ .status = NFS3ERR_EXIST }; + rpc_queue_reply(rop); + return 0; + } + // FIXME: Persist empty directories in some etcd keys, like /vitastor/dir/... + self->parent->dir_info[full_name] = (nfs_dir_t){ + .id = self->parent->next_dir_id++, + .mod_rev = 0, + }; + self->parent->dir_by_hash["S"+base64_encode(sha256(full_name))] = full_name; + *reply = (MKDIR3res){ + .status = NFS3_OK, + .resok = (MKDIR3resok){ + .obj = { + .handle_follows = 1, + .handle = xdr_copy_string(rop->xdrs, "S"+base64_encode(sha256(full_name))), + }, + .obj_attributes = { + .attributes_follow = 1, + .attributes = get_dir_attributes(self, full_name), + }, + //.dir_wcc = ... + }, + }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_symlink_proc(void *opaque, rpc_op_t *rop) +{ +// nfs_client_t *self = (nfs_client_t*)opaque; +// SYMLINK3args *args = (SYMLINK3args*)rop->request; + SYMLINK3res *reply = (SYMLINK3res*)rop->reply; + // Not supported yet + *reply = (SYMLINK3res){ .status = NFS3ERR_NOTSUPP }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_mknod_proc(void *opaque, rpc_op_t *rop) +{ +// nfs_client_t *self = (nfs_client_t*)opaque; +// MKNOD3args *args = (MKNOD3args*)rop->request; + MKNOD3res *reply = (MKNOD3res*)rop->reply; + // Not supported yet + *reply = (MKNOD3res){ .status = NFS3ERR_NOTSUPP }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_remove_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + REMOVE3res *reply = (REMOVE3res*)rop->reply; + REMOVE3args *args = (REMOVE3args*)rop->request; + std::string full_name = get_inode_name(self, args->object); + if (full_name == "") + { + *reply = (REMOVE3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + // Run rm command + self->parent->cmd->loop_and_wait(self->parent->cmd->start_rm(json11::Json::object { + { "from", full_name }, + }), [rop](const cli_result_t & r) + { + REMOVE3res *reply = (REMOVE3res*)rop->reply; + *reply = (REMOVE3res){ .status = vitastor_nfs_map_err(r.err) }; + if (!r.err) + { + reply->resok = (REMOVE3resok){ + //.dir_wcc = ... + }; + } + rpc_queue_reply(rop); + }); + return 1; +} + +static int nfs3_rmdir_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + RMDIR3args *args = (RMDIR3args*)rop->request; + RMDIR3res *reply = (RMDIR3res*)rop->reply; + std::string full_name = get_inode_name(self, args->object); + if (full_name == "") + { + *reply = (RMDIR3res){ .status = NFS3ERR_INVAL }; + rpc_queue_reply(rop); + return 0; + } + auto dir_it = self->parent->dir_info.find(full_name); + if (dir_it == self->parent->dir_info.end()) + { + *reply = (RMDIR3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + std::string prefix = full_name+"/"; + for (auto & ic: self->parent->cli->st_cli.inode_config) + { + if (prefix != "" && ic.second.name.substr(0, prefix.size()) == prefix) + { + *reply = (RMDIR3res){ .status = NFS3ERR_NOTEMPTY }; + rpc_queue_reply(rop); + return 0; + } + } + self->parent->dir_by_hash.erase("S"+base64_encode(sha256(full_name))); + self->parent->dir_info.erase(dir_it); + *reply = (RMDIR3res){ .status = NFS3_OK }; + rpc_queue_reply(rop); + return 0; +} + +struct nfs_dir_rename_state +{ + nfs_client_t *self; + rpc_op_t *rop; + std::string old_name, new_name; + std::vector items; +}; + +static int continue_dir_rename(nfs_dir_rename_state *rename_st) +{ + nfs_client_t *self = rename_st->self; + if (!rename_st->items.size()) + { + std::string old_prefix = rename_st->old_name+"/"; + for (auto & ic: self->parent->cli->st_cli.inode_config) + { + if (ic.second.name.substr(0, old_prefix.size()) == old_prefix) + rename_st->items.push_back(ic.second.name); + } + } + if (!rename_st->items.size()) + { + // old dir + auto old_info = self->parent->dir_info.at(rename_st->old_name); + self->parent->dir_info.erase(rename_st->old_name); + self->parent->dir_by_hash.erase("S"+base64_encode(sha256(rename_st->old_name))); + // new dir + self->parent->dir_info[rename_st->new_name] = old_info; + self->parent->dir_by_hash["S"+base64_encode(sha256(rename_st->new_name))] = rename_st->new_name; + RENAME3res *reply = (RENAME3res*)rename_st->rop->reply; + *reply = (RENAME3res){ + .status = NFS3_OK, + .resok = { + //.fromdir_wcc = ... + //.todir_wcc = ... + }, + }; + rpc_queue_reply(rename_st->rop); + delete rename_st; + return 0; + } + std::string item = rename_st->items.back(); + rename_st->items.pop_back(); + self->parent->cmd->loop_and_wait(self->parent->cmd->start_modify(json11::Json::object { + { "image", item }, + { "rename", rename_st->new_name + item.substr(rename_st->old_name.size()) }, + }), [rename_st](const cli_result_t & r) + { + if (r.err) + { + RENAME3res *reply = (RENAME3res*)rename_st->rop->reply; + *reply = (RENAME3res){ .status = vitastor_nfs_map_err(r.err) }; + rpc_queue_reply(rename_st->rop); + delete rename_st; + } + else + { + continue_dir_rename(rename_st); + } + }); + return 1; +} + +static void nfs_do_rename(nfs_client_t *self, rpc_op_t *rop, std::string old_name, std::string new_name); + +static int nfs3_rename_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + RENAME3args *args = (RENAME3args*)rop->request; + std::string old_name = get_inode_name(self, args->from); + std::string new_name = get_inode_name(self, args->to); + if (old_name == "" || new_name == "") + { + RENAME3res *reply = (RENAME3res*)rop->reply; + *reply = (RENAME3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + bool old_is_dir = self->parent->dir_info.find(old_name) != self->parent->dir_info.end(); + bool new_is_dir = self->parent->dir_info.find(new_name) != self->parent->dir_info.end(); + bool old_is_file = false, new_is_file = false; + for (auto & ic: self->parent->cli->st_cli.inode_config) + { + if (ic.second.name == new_name) + new_is_file = true; + if (ic.second.name == old_name) + old_is_file = true; + if (new_is_file && old_is_file) + break; + } + if (old_is_dir) + { + // Check that destination is not a file + if (new_is_file) + { + RENAME3res *reply = (RENAME3res*)rop->reply; + *reply = (RENAME3res){ .status = NFS3ERR_NOTDIR }; + rpc_queue_reply(rop); + return 0; + } + // Rename all images with this prefix + nfs_dir_rename_state *rename_st = new nfs_dir_rename_state(); + rename_st->self = self; + rename_st->rop = rop; + rename_st->old_name = old_name; + rename_st->new_name = new_name; + return continue_dir_rename(rename_st); + } + if (!old_is_file) + { + RENAME3res *reply = (RENAME3res*)rop->reply; + *reply = (RENAME3res){ .status = NFS3ERR_NOENT }; + rpc_queue_reply(rop); + return 0; + } + if (new_is_dir) + { + RENAME3res *reply = (RENAME3res*)rop->reply; + *reply = (RENAME3res){ .status = NFS3ERR_ISDIR }; + rpc_queue_reply(rop); + return 0; + } + if (new_is_file) + { + // Rename over an existing file - remove old file + self->parent->cmd->loop_and_wait(self->parent->cmd->start_rm(json11::Json::object { + { "from", new_name }, + }), [self, rop, old_name, new_name](const cli_result_t & r) + { + nfs_do_rename(self, rop, old_name, new_name); + }); + } + else + { + nfs_do_rename(self, rop, old_name, new_name); + } + return 1; +} + +static void nfs_do_rename(nfs_client_t *self, rpc_op_t *rop, std::string old_name, std::string new_name) +{ + // Run modify/rename command + self->parent->cmd->loop_and_wait(self->parent->cmd->start_modify(json11::Json::object { + { "image", old_name }, + { "rename", new_name }, + }), [rop](const cli_result_t & r) + { + RENAME3res *reply = (RENAME3res*)rop->reply; + *reply = (RENAME3res){ .status = vitastor_nfs_map_err(r.err) }; + if (!r.err) + { + reply->resok = (RENAME3resok){ + //.fromdir_wcc = ... + //.todir_wcc = ... + }; + } + rpc_queue_reply(rop); + }); +} + +static int nfs3_link_proc(void *opaque, rpc_op_t *rop) +{ + //nfs_client_t *self = (nfs_client_t*)opaque; + //LINK3args *args = (LINK3args*)rop->request; + LINK3res *reply = (LINK3res*)rop->reply; + // We don't support hard links + *reply = (LINK3res){ NFS3ERR_NOTSUPP }; + rpc_queue_reply(rop); + return 0; +} + +static void nfs3_readdir_common(void *opaque, rpc_op_t *rop, bool is_plus) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + READDIRPLUS3args plus_args; + READDIRPLUS3args *args = NULL; + if (is_plus) + args = ((READDIRPLUS3args*)rop->request); + else + { + args = &plus_args; + READDIR3args *in_args = ((READDIR3args*)rop->request); + args->dir = in_args->dir; + args->cookie = in_args->cookie; + *((uint64_t*)args->cookieverf) = *((uint64_t*)in_args->cookieverf); + args->dircount = 512; + args->maxcount = in_args->count; + } + std::string dirhash = args->dir; + std::string dir; + if (dirhash != "roothandle") + { + auto dir_it = self->parent->dir_by_hash.find(dirhash); + if (dir_it != self->parent->dir_by_hash.end()) + dir = dir_it->second; + } + std::string prefix = dir.size() ? dir+"/" : self->parent->name_prefix; + std::map entries; + for (auto & ic: self->parent->cli->st_cli.inode_config) + { + auto & inode_cfg = ic.second; + if (prefix != "" && inode_cfg.name.substr(0, prefix.size()) != prefix) + continue; + std::string subname = inode_cfg.name.substr(prefix.size()); + int p = 0; + while (p < subname.size() && subname[p] == '/') + p++; + if (p > 0) + subname = subname.substr(p); + if (subname.size() == 0) + continue; + p = 0; + while (p < subname.size() && subname[p] != '/') + p++; + if (p >= subname.size()) + { + // fileid will change when the user creates snapshots + // however, we hope that clients tolerate it well + // Linux does, even though it complains about "fileid changed" in dmesg + entries[subname].fileid = ic.first; + if (is_plus) + { + entries[subname].name_attributes = (post_op_attr){ + .attributes_follow = 1, + .attributes = get_file_attributes(self, ic.first), + }; + entries[subname].name_handle = (post_op_fh3){ + .handle_follows = 1, + .handle = xdr_copy_string(rop->xdrs, "S"+base64_encode(sha256(inode_cfg.name))), + }; + } + } + else + { + // skip directories, they will be added from dir_info + } + } + // Add directories from dir_info + for (auto dir_id_it = self->parent->dir_info.lower_bound(prefix); + dir_id_it != self->parent->dir_info.end(); dir_id_it++) + { + if (prefix != "" && dir_id_it->first.substr(0, prefix.size()) != prefix) + break; + if (dir_id_it->first.size() == prefix.size() || + dir_id_it->first.find("/", prefix.size()) != std::string::npos) + continue; + std::string subname = dir_id_it->first.substr(prefix.size()); + // for directories, fileid changes when the user restarts proxy + entries[subname].fileid = dir_id_it->second.id; + if (is_plus) + { + entries[subname].name_attributes = (post_op_attr){ + .attributes_follow = 1, + .attributes = get_dir_attributes(self, dir_id_it->first), + }; + entries[subname].name_handle = (post_op_fh3){ + .handle_follows = 1, + .handle = xdr_copy_string(rop->xdrs, "S"+base64_encode(sha256(dir_id_it->first))), + }; + } + } + // Offset results by the continuation cookie (equal to index in the listing) + uint64_t idx = 1; + void *prev = NULL; + for (auto it = entries.begin(); it != entries.end();) + { + entryplus3 *entry = &it->second; + // First fields of entry3 and entryplus3 are the same: fileid, name, cookie + entry->name = xdr_copy_string(rop->xdrs, it->first); + entry->cookie = idx++; + if (prev) + { + if (is_plus) + ((entryplus3*)prev)->nextentry = entry; + else + ((entry3*)prev)->nextentry = (entry3*)entry; + } + prev = entry; + if (args->cookie > 0 && entry->cookie == args->cookie) + entries.erase(entries.begin(), ++it); + else + it++; + } + // Now limit results based on maximum reply size + // Sadly we have to calculate reply size by hand + // reply without entries is 4+4+(dir_attributes ? sizeof(fattr3) : 0)+8+4 bytes + int reply_size = 20; + if (reply_size > args->maxcount) + { + // Error, too small max reply size + if (is_plus) + { + READDIRPLUS3res *reply = (READDIRPLUS3res*)rop->reply; + *reply = (READDIRPLUS3res){ .status = NFS3ERR_TOOSMALL }; + rpc_queue_reply(rop); + } + else + { + READDIR3res *reply = (READDIR3res*)rop->reply; + *reply = (READDIR3res){ .status = NFS3ERR_TOOSMALL }; + rpc_queue_reply(rop); + } + return; + } + // 1 entry3 is (8+4+(filename_len+3)/4*4+8) bytes + // 1 entryplus3 is (8+4+(filename_len+3)/4*4+8 + // + 4+(name_attributes ? (sizeof(fattr3) = 84) : 0) + // + 4+(name_handle ? 4+(handle_len+3)/4*4 : 0)) bytes + bool eof = true; + for (auto it = entries.begin(); it != entries.end(); it++) + { + reply_size += 20+len_pad4(it->first.size())+(is_plus + ? 8+88+len_pad4(it->second.name_handle.handle.size) : 0); + if (reply_size > args->maxcount) + { + // Stop + entries.erase(it, entries.end()); + eof = false; + break; + } + } + if (entries.end() != entries.begin()) + { + auto last_it = entries.end(); + last_it--; + if (is_plus) + ((entryplus3*)&last_it->second)->nextentry = NULL; + else + { + entry3* e = ((entry3*)&last_it->second); + e->nextentry = NULL; + } + } + // Send reply + if (is_plus) + { + READDIRPLUS3res *reply = (READDIRPLUS3res*)rop->reply; + *reply = { .status = NFS3_OK }; + *(uint64_t*)(reply->resok.cookieverf) = self->parent->dir_info.at(dir).mod_rev; + reply->resok.reply.entries = entries.size() ? &entries.begin()->second : NULL; + reply->resok.reply.eof = eof; + } + else + { + READDIR3res *reply = (READDIR3res*)rop->reply; + *reply = { .status = NFS3_OK }; + *(uint64_t*)(reply->resok.cookieverf) = self->parent->dir_info.at(dir).mod_rev; + reply->resok.reply.entries = entries.size() ? (entry3*)&entries.begin()->second : NULL; + reply->resok.reply.eof = eof; + } + rpc_queue_reply(rop); +} + +static int nfs3_readdir_proc(void *opaque, rpc_op_t *rop) +{ + nfs3_readdir_common(opaque, rop, false); + return 0; +} + +static int nfs3_readdirplus_proc(void *opaque, rpc_op_t *rop) +{ + nfs3_readdir_common(opaque, rop, true); + return 0; +} + +// Get file system statistics +static int nfs3_fsstat_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + //FSSTAT3args *args = (FSSTAT3args*)rop->request; + FSSTAT3res *reply = (FSSTAT3res*)rop->reply; + uint64_t tbytes = 0, fbytes = 0; + auto pst_it = self->parent->pool_stats.find(self->parent->default_pool_id); + if (pst_it != self->parent->pool_stats.end()) + { + auto ttb = pst_it->second["total_raw_tb"].number_value(); + auto ftb = (pst_it->second["total_raw_tb"].number_value() - pst_it->second["used_raw_tb"].number_value()); + tbytes = ttb / pst_it->second["raw_to_usable"].number_value() * ((uint64_t)2<<40); + fbytes = ftb / pst_it->second["raw_to_usable"].number_value() * ((uint64_t)2<<40); + } + *reply = (FSSTAT3res){ + .status = NFS3_OK, + .resok = (FSSTAT3resok){ + .obj_attributes = { + .attributes_follow = 1, + .attributes = get_dir_attributes(self, ""), + }, + .tbytes = tbytes, // total bytes + .fbytes = fbytes, // free bytes + .abytes = fbytes, // available bytes + .tfiles = (size3)(1 << 31), // maximum total files + .ffiles = (size3)(1 << 31), // free files + .afiles = (size3)(1 << 31), // available files + .invarsec = 0, + }, + }; + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_fsinfo_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + FSINFO3args *args = (FSINFO3args*)rop->request; + FSINFO3res *reply = (FSINFO3res*)rop->reply; + if (args->fsroot != "roothandle") + { + // Example error + *reply = (FSINFO3res){ .status = NFS3ERR_INVAL }; + } + else + { + // Fill info + *reply = (FSINFO3res){ + .status = NFS3_OK, + .resok = (FSINFO3resok){ + .obj_attributes = { + .attributes_follow = 1, + .attributes = get_dir_attributes(self, ""), + }, + .rtmax = 128*1024*1024, + .rtpref = 128*1024*1024, + .rtmult = 4096, + .wtmax = 128*1024*1024, + .wtpref = 128*1024*1024, + .wtmult = 4096, + .dtpref = 128, + .maxfilesize = 0x7fffffffffffffff, + .time_delta = { + .seconds = 1, + .nseconds = 0, + }, + .properties = FSF3_SYMLINK | FSF3_HOMOGENEOUS, + }, + }; + } + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_pathconf_proc(void *opaque, rpc_op_t *rop) +{ + //nfs_client_t *self = (nfs_client_t*)opaque; + PATHCONF3args *args = (PATHCONF3args*)rop->request; + PATHCONF3res *reply = (PATHCONF3res*)rop->reply; + if (args->object != "roothandle") + { + // Example error + *reply = (PATHCONF3res){ .status = NFS3ERR_INVAL }; + } + else + { + // Fill info + *reply = (PATHCONF3res){ + .status = NFS3_OK, + .resok = (PATHCONF3resok){ + .obj_attributes = { + .attributes_follow = FALSE, + }, + .linkmax = 0, + .name_max = 255, + .no_trunc = TRUE, + .chown_restricted = FALSE, + .case_insensitive = FALSE, + .case_preserving = TRUE, + }, + }; + } + rpc_queue_reply(rop); + return 0; +} + +static int nfs3_commit_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + //COMMIT3args *args = (COMMIT3args*)rop->request; + if (!self->parent->cli->get_immediate_commit()) + { + cluster_op_t *op = new cluster_op_t; + // fsync. we don't know how to fsync a single inode, so just fsync everything + op->opcode = OSD_OP_SYNC; + op->callback = [rop](cluster_op_t *op) + { + COMMIT3res *reply = (COMMIT3res*)rop->reply; + *reply = (COMMIT3res){ .status = vitastor_nfs_map_err(op->retval) }; + rpc_queue_reply(rop); + }; + self->parent->cli->execute(op); + return 1; + } + // pretend we just did an fsync + COMMIT3res *reply = (COMMIT3res*)rop->reply; + *reply = (COMMIT3res){ .status = NFS3_OK }; + rpc_queue_reply(rop); + return 0; +} + +static int mount3_mnt_proc(void *opaque, rpc_op_t *rop) +{ + //nfs_client_t *self = (nfs_client_t*)opaque; + //nfs_dirpath *args = (nfs_dirpath*)rop->request; + nfs_mountres3 *reply = (nfs_mountres3*)rop->reply; + u_int flavor = RPC_AUTH_NONE; + reply->fhs_status = MNT3_OK; + reply->mountinfo.fhandle = xdr_copy_string(rop->xdrs, "roothandle"); + reply->mountinfo.auth_flavors.auth_flavors_len = 1; + reply->mountinfo.auth_flavors.auth_flavors_val = (u_int*)xdr_copy_string(rop->xdrs, (char*)&flavor, sizeof(u_int)).data; + rpc_queue_reply(rop); + return 0; +} + +static int mount3_dump_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + nfs_mountlist *reply = (nfs_mountlist*)rop->reply; + *reply = (struct nfs_mountbody*)malloc_or_die(sizeof(struct nfs_mountbody)); + xdr_add_malloc(rop->xdrs, *reply); + (*reply)->ml_hostname = xdr_copy_string(rop->xdrs, "127.0.0.1"); + (*reply)->ml_directory = xdr_copy_string(rop->xdrs, self->parent->export_root); + (*reply)->ml_next = NULL; + rpc_queue_reply(rop); + return 0; +} + +static int mount3_umnt_proc(void *opaque, rpc_op_t *rop) +{ + //nfs_client_t *self = (nfs_client_t*)opaque; + //nfs_dirpath *arg = (nfs_dirpath*)rop->request; + // do nothing + rpc_queue_reply(rop); + return 0; +} + +static int mount3_umntall_proc(void *opaque, rpc_op_t *rop) +{ + // do nothing + rpc_queue_reply(rop); + return 0; +} + +static int mount3_export_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + nfs_exports *reply = (nfs_exports*)rop->reply; + *reply = (struct nfs_exportnode*)malloc(sizeof(struct nfs_exportnode) + sizeof(struct nfs_groupnode)); + xdr_add_malloc(rop->xdrs, *reply); + (*reply)->ex_dir = xdr_copy_string(rop->xdrs, self->parent->export_root); + (*reply)->ex_groups = (struct nfs_groupnode*)(reply+1); + (*reply)->ex_groups->gr_name = xdr_copy_string(rop->xdrs, "127.0.0.1"); + (*reply)->ex_groups->gr_next = NULL; + (*reply)->ex_next = NULL; + rpc_queue_reply(rop); + return 0; +} + +nfs_client_t::nfs_client_t() +{ + struct rpc_service_proc_t pt[] = { + {NFS_PROGRAM, NFS_V3, NFS3_NULL, nfs3_null_proc, NULL, 0, NULL, 0, this}, + {NFS_PROGRAM, NFS_V3, NFS3_GETATTR, nfs3_getattr_proc, (xdrproc_t)xdr_GETATTR3args, sizeof(GETATTR3args), (xdrproc_t)xdr_GETATTR3res, sizeof(GETATTR3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_SETATTR, nfs3_setattr_proc, (xdrproc_t)xdr_SETATTR3args, sizeof(SETATTR3args), (xdrproc_t)xdr_SETATTR3res, sizeof(SETATTR3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_LOOKUP, nfs3_lookup_proc, (xdrproc_t)xdr_LOOKUP3args, sizeof(LOOKUP3args), (xdrproc_t)xdr_LOOKUP3res, sizeof(LOOKUP3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_ACCESS, nfs3_access_proc, (xdrproc_t)xdr_ACCESS3args, sizeof(ACCESS3args), (xdrproc_t)xdr_ACCESS3res, sizeof(ACCESS3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_READLINK, nfs3_readlink_proc, (xdrproc_t)xdr_READLINK3args, sizeof(READLINK3args), (xdrproc_t)xdr_READLINK3res, sizeof(READLINK3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_READ, nfs3_read_proc, (xdrproc_t)xdr_READ3args, sizeof(READ3args), (xdrproc_t)xdr_READ3res, sizeof(READ3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_WRITE, nfs3_write_proc, (xdrproc_t)xdr_WRITE3args, sizeof(WRITE3args), (xdrproc_t)xdr_WRITE3res, sizeof(WRITE3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_CREATE, nfs3_create_proc, (xdrproc_t)xdr_CREATE3args, sizeof(CREATE3args), (xdrproc_t)xdr_CREATE3res, sizeof(CREATE3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_MKDIR, nfs3_mkdir_proc, (xdrproc_t)xdr_MKDIR3args, sizeof(MKDIR3args), (xdrproc_t)xdr_MKDIR3res, sizeof(MKDIR3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_SYMLINK, nfs3_symlink_proc, (xdrproc_t)xdr_SYMLINK3args, sizeof(SYMLINK3args), (xdrproc_t)xdr_SYMLINK3res, sizeof(SYMLINK3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_MKNOD, nfs3_mknod_proc, (xdrproc_t)xdr_MKNOD3args, sizeof(MKNOD3args), (xdrproc_t)xdr_MKNOD3res, sizeof(MKNOD3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_REMOVE, nfs3_remove_proc, (xdrproc_t)xdr_REMOVE3args, sizeof(REMOVE3args), (xdrproc_t)xdr_REMOVE3res, sizeof(REMOVE3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_RMDIR, nfs3_rmdir_proc, (xdrproc_t)xdr_RMDIR3args, sizeof(RMDIR3args), (xdrproc_t)xdr_RMDIR3res, sizeof(RMDIR3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_RENAME, nfs3_rename_proc, (xdrproc_t)xdr_RENAME3args, sizeof(RENAME3args), (xdrproc_t)xdr_RENAME3res, sizeof(RENAME3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_LINK, nfs3_link_proc, (xdrproc_t)xdr_LINK3args, sizeof(LINK3args), (xdrproc_t)xdr_LINK3res, sizeof(LINK3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_READDIR, nfs3_readdir_proc, (xdrproc_t)xdr_READDIR3args, sizeof(READDIR3args), (xdrproc_t)xdr_READDIR3res, sizeof(READDIR3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_READDIRPLUS, nfs3_readdirplus_proc, (xdrproc_t)xdr_READDIRPLUS3args, sizeof(READDIRPLUS3args), (xdrproc_t)xdr_READDIRPLUS3res, sizeof(READDIRPLUS3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_FSSTAT, nfs3_fsstat_proc, (xdrproc_t)xdr_FSSTAT3args, sizeof(FSSTAT3args), (xdrproc_t)xdr_FSSTAT3res, sizeof(FSSTAT3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_FSINFO, nfs3_fsinfo_proc, (xdrproc_t)xdr_FSINFO3args, sizeof(FSINFO3args), (xdrproc_t)xdr_FSINFO3res, sizeof(FSINFO3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_PATHCONF, nfs3_pathconf_proc, (xdrproc_t)xdr_PATHCONF3args, sizeof(PATHCONF3args), (xdrproc_t)xdr_PATHCONF3res, sizeof(PATHCONF3res), this}, + {NFS_PROGRAM, NFS_V3, NFS3_COMMIT, nfs3_commit_proc, (xdrproc_t)xdr_COMMIT3args, sizeof(COMMIT3args), (xdrproc_t)xdr_COMMIT3res, sizeof(COMMIT3res), this}, + {MOUNT_PROGRAM, MOUNT_V3, MOUNT3_NULL, nfs3_null_proc, NULL, 0, NULL, 0, this}, + {MOUNT_PROGRAM, MOUNT_V3, MOUNT3_MNT, mount3_mnt_proc, (xdrproc_t)xdr_nfs_dirpath, sizeof(nfs_dirpath), (xdrproc_t)xdr_nfs_mountres3, sizeof(nfs_mountres3), this}, + {MOUNT_PROGRAM, MOUNT_V3, MOUNT3_DUMP, mount3_dump_proc, NULL, 0, (xdrproc_t)xdr_nfs_mountlist, sizeof(nfs_mountlist), this}, + {MOUNT_PROGRAM, MOUNT_V3, MOUNT3_UMNT, mount3_umnt_proc, (xdrproc_t)xdr_nfs_dirpath, sizeof(nfs_dirpath), NULL, 0, this}, + {MOUNT_PROGRAM, MOUNT_V3, MOUNT3_UMNTALL, mount3_umntall_proc, NULL, 0, NULL, 0, this}, + {MOUNT_PROGRAM, MOUNT_V3, MOUNT3_EXPORT, mount3_export_proc, NULL, 0, (xdrproc_t)xdr_nfs_exports, sizeof(nfs_exports), this}, + }; + for (int i = 0; i < sizeof(pt)/sizeof(pt[0]); i++) + { + proc_table.insert(pt[i]); + } +} + +nfs_client_t::~nfs_client_t() +{ +} diff --git a/src/nfs_portmap.cpp b/src/nfs_portmap.cpp new file mode 100644 index 000000000..96c571942 --- /dev/null +++ b/src/nfs_portmap.cpp @@ -0,0 +1,184 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) +// +// Portmap service for NFS proxy + +#include +#include + +#include "nfs/portmap.h" +#include "nfs/xdr_impl_inline.h" + +#include "malloc_or_die.h" +#include "nfs_portmap.h" +#include "sha256.h" +#include "base64.h" + +/* + * The NULL procedure. All protocols/versions must provide a NULL procedure + * as index 0. + * It is used by clients, and rpcinfo, to "ping" a service and verify that + * the service is available and that it does support the indicated version. + */ +static int pmap2_null_proc(struct rpc_context *rpc, rpc_op_t *rop) +{ + rpc_queue_reply(rop); + return 0; +} + +/* + * v2 GETPORT. + * This is the lookup function for portmapper version 2. + * A client provides program, version and protocol (tcp or udp) + * and portmapper returns which port that service is available on, + * (or 0 if no such program is registered.) + */ +static int pmap2_getport_proc(portmap_service_t *self, rpc_op_t *rop) +{ + PMAP2GETPORTargs *args = (PMAP2GETPORTargs *)rop->request; + uint32_t *reply = (uint32_t *)rop->reply; + auto it = self->reg_ports.lower_bound((portmap_id_t){ + .prog = args->prog, + .vers = args->vers, + .udp = args->prot == IPPROTO_UDP, + .ipv6 = false, + }); + if (it != self->reg_ports.end() && + it->prog == args->prog && it->vers == args->vers && + it->udp == (args->prot == IPPROTO_UDP)) + { + *reply = it->port; + } + else + { + *reply = 0; + } + rpc_queue_reply(rop); + return 0; +} + +/* + * v2 DUMP. + * This RPC returns a list of all endpoints that are registered with + * portmapper. + */ +static int pmap2_dump_proc(portmap_service_t *self, rpc_op_t *rop) +{ + pmap2_mapping_list *list = (pmap2_mapping_list*)malloc_or_die(sizeof(pmap2_mapping_list) * self->reg_ports.size()); + xdr_add_malloc(rop->xdrs, list); + PMAP2DUMPres *reply = (PMAP2DUMPres *)rop->reply; + int i = 0; + for (auto it = self->reg_ports.begin(); it != self->reg_ports.end(); it++) + { + if (it->ipv6) + continue; + list[i] = { + .map = { + .prog = it->prog, + .vers = it->vers, + .prot = it->udp ? IPPROTO_UDP : IPPROTO_TCP, + .port = it->port, + }, + .next = list+i+1, + }; + i++; + } + list[i-1].next = NULL; + // Send reply + reply->list = list; + rpc_queue_reply(rop); + return 0; +} + +/* + * v3 GETADDR. + * This is the lookup function for portmapper version 3. + */ +static int pmap3_getaddr_proc(portmap_service_t *self, rpc_op_t *rop) +{ + PMAP3GETADDRargs *args = (PMAP3GETADDRargs *)rop->request; + PMAP3GETADDRres *reply = (PMAP3GETADDRres *)rop->reply; + portmap_id_t ref = (portmap_id_t){ + .prog = args->prog, + .vers = args->vers, + .udp = args->netid == "udp" || args->netid == "udp6", + .ipv6 = args->netid == "tcp6" || args->netid == "udp6", + }; + auto it = self->reg_ports.lower_bound(ref); + if (it != self->reg_ports.end() && + it->prog == ref.prog && it->vers == ref.vers && + it->udp == ref.udp && it->ipv6 == ref.ipv6) + { + reply->addr = xdr_copy_string(rop->xdrs, it->addr); + } + else + { + reply->addr = {}; + } + rpc_queue_reply(rop); + return 0; +} + +/* + * v3 DUMP. + * This RPC returns a list of all endpoints that are registered with + * portmapper. + */ +static std::string netid_udp = "udp"; +static std::string netid_udp6 = "udp6"; +static std::string netid_tcp = "tcp"; +static std::string netid_tcp6 = "tcp6"; +static int pmap3_dump_proc(portmap_service_t *self, rpc_op_t *rop) +{ + PMAP3DUMPres *reply = (PMAP3DUMPres *)rop->reply; + pmap3_mapping_list *list = (pmap3_mapping_list*)malloc(sizeof(pmap3_mapping_list*) * self->reg_ports.size()); + xdr_add_malloc(rop->xdrs, list); + int i = 0; + for (auto it = self->reg_ports.begin(); it != self->reg_ports.end(); it++) + { + list[i] = (pmap3_mapping_list){ + .map = (pmap3_mapping){ + .prog = it->prog, + .vers = it->vers, + .netid = xdr_copy_string(rop->xdrs, it->ipv6 + ? (it->udp ? netid_udp6 : netid_tcp6) + : (it->udp ? netid_udp : netid_tcp)), + .addr = xdr_copy_string(rop->xdrs, it->addr), // 0.0.0.0.port + .owner = xdr_copy_string(rop->xdrs, it->owner), + }, + .next = list+i+1, + }; + i++; + } + list[i-1].next = NULL; + reply->list = list; + rpc_queue_reply(rop); + return 0; +} + +portmap_service_t::portmap_service_t() +{ + struct rpc_service_proc_t pt[] = { + {PMAP_PROGRAM, PMAP_V2, PMAP2_NULL, (rpc_handler_t)pmap2_null_proc, NULL, 0, NULL, 0, this}, + {PMAP_PROGRAM, PMAP_V2, PMAP2_GETPORT, (rpc_handler_t)pmap2_getport_proc, (xdrproc_t)xdr_PMAP2GETPORTargs, sizeof(PMAP2GETPORTargs), (xdrproc_t)xdr_u_int, sizeof(u_int), this}, + {PMAP_PROGRAM, PMAP_V2, PMAP2_DUMP, (rpc_handler_t)pmap2_dump_proc, NULL, 0, (xdrproc_t)xdr_PMAP2DUMPres, sizeof(PMAP2DUMPres), this}, + {PMAP_PROGRAM, PMAP_V3, PMAP3_NULL, (rpc_handler_t)pmap2_null_proc, NULL, 0, NULL, 0, this}, + {PMAP_PROGRAM, PMAP_V3, PMAP3_GETADDR, (rpc_handler_t)pmap3_getaddr_proc, (xdrproc_t)xdr_PMAP3GETADDRargs, sizeof(PMAP3GETADDRargs), (xdrproc_t)xdr_string, sizeof(xdr_string_t), this}, + {PMAP_PROGRAM, PMAP_V3, PMAP3_DUMP, (rpc_handler_t)pmap3_dump_proc, NULL, 0, (xdrproc_t)xdr_PMAP3DUMPres, sizeof(PMAP3DUMPres), this}, + }; + for (int i = 0; i < sizeof(pt)/sizeof(pt[0]); i++) + { + proc_table.push_back(pt[i]); + } +} + +std::string sha256(const std::string & str) +{ + std::string hash; + hash.resize(32); + SHA256_CTX ctx; + sha256_init(&ctx); + sha256_update(&ctx, (uint8_t*)str.data(), str.size()); + sha256_final(&ctx, (uint8_t*)hash.data()); + return hash; +} diff --git a/src/nfs_portmap.h b/src/nfs_portmap.h new file mode 100644 index 000000000..efaa0abf1 --- /dev/null +++ b/src/nfs_portmap.h @@ -0,0 +1,39 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) +// +// Portmap service for NFS proxy + +#pragma once + +#include +#include +#include + +#include "nfs/rpc_impl.h" + +struct portmap_id_t +{ + unsigned prog, vers; + bool udp; + bool ipv6; + unsigned port; + std::string owner; + std::string addr; +}; + +class portmap_service_t +{ +public: + std::set reg_ports; + std::vector proc_table; + portmap_service_t(); +}; + +inline bool operator < (const portmap_id_t &a, const portmap_id_t &b) +{ + return a.prog < b.prog || a.prog == b.prog && a.vers < b.vers || + a.prog == b.prog && a.vers == b.vers && a.udp < b.udp || + a.prog == b.prog && a.vers == b.vers && a.udp == b.udp && a.ipv6 < b.ipv6; +} + +std::string sha256(const std::string & str); diff --git a/src/nfs_proxy.cpp b/src/nfs_proxy.cpp new file mode 100644 index 000000000..1c759bd3f --- /dev/null +++ b/src/nfs_proxy.cpp @@ -0,0 +1,972 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) +// +// Simplified NFS proxy +// Presents all images as files +// Keeps image/file list in memory and is thus unsuitable for a large number of files + +#define _XOPEN_SOURCE +#include +#include + +#include +#include +#include +#include +//#include + +#include "nfs/nfs.h" +#include "nfs/rpc.h" +#include "nfs/portmap.h" + +#include "addr_util.h" +#include "base64.h" +#include "nfs_proxy.h" +#include "http_client.h" +#include "cli.h" + +#define ETCD_INODE_STATS_WATCH_ID 101 +#define ETCD_POOL_STATS_WATCH_ID 102 + +const char *exe_name = NULL; + +nfs_proxy_t::~nfs_proxy_t() +{ + if (cmd) + delete cmd; + if (cli) + delete cli; + if (epmgr) + delete epmgr; + if (ringloop) + delete ringloop; +} + +json11::Json::object nfs_proxy_t::parse_args(int narg, const char *args[]) +{ + json11::Json::object cfg; + for (int i = 1; i < narg; i++) + { + if (!strcmp(args[i], "-h") || !strcmp(args[i], "--help")) + { + printf( + "Vitastor NFS 3.0 proxy\n" + "(c) Vitaliy Filippov, 2021-2022 (VNPL-1.1)\n" + "\n" + "USAGE:\n" + " %s [--etcd_address ADDR] [OTHER OPTIONS]\n" + " --subdir export images prefixed / (default empty - export all images)\n" + " --portmap 0 do not listen on port 111 (portmap/rpcbind, requires root)\n" + " --bind bind service to address (default 0.0.0.0)\n" + " --nfspath set NFS export path to (default is /)\n" + " --port use port for NFS services (default is 2049)\n" + " --pool use as default pool for new files (images)\n" + " --foreground 1 stay in foreground, do not daemonize\n" + "\n" + "NFS proxy is stateless if you use immediate_commit=all in your cluster, so\n" + "you can freely use multiple NFS proxies with L3 load balancing in this case.\n" + "\n" + "Example start and mount commands for a custom NFS port:\n" + " %s --etcd_address 192.168.5.10:2379 --portmap 0 --port 2050 --pool testpool\n" + " mount localhost:/ /mnt/ -o port=2050,mountport=2050,nfsvers=3,soft,nolock,tcp\n", + exe_name, exe_name + ); + exit(0); + } + else if (args[i][0] == '-' && args[i][1] == '-') + { + const char *opt = args[i]+2; + cfg[opt] = !strcmp(opt, "json") || i == narg-1 ? "1" : args[++i]; + } + } + return cfg; +} + +void nfs_proxy_t::run(json11::Json cfg) +{ + while (getrandom(&server_id, sizeof(server_id), 0) != sizeof(server_id)) {} + // Parse options + bind_address = cfg["bind"].string_value(); + if (bind_address == "") + bind_address = "0.0.0.0"; + default_pool = cfg["pool"].as_string(); + portmap_enabled = cfg.object_items().find("portmap") == cfg.object_items().end() || + cfg["portmap"].uint64_value() || + cfg["portmap"].string_value() == "yes" || + cfg["portmap"].string_value() == "true"; + nfs_port = cfg["port"].uint64_value() & 0xffff; + if (!nfs_port) + nfs_port = 2049; + export_root = cfg["nfspath"].string_value(); + if (!export_root.size()) + export_root = "/"; + name_prefix = cfg["subdir"].string_value(); + { + int e = name_prefix.size(); + while (e > 0 && name_prefix[e-1] == '/') + e--; + int s = 0; + while (s < e && name_prefix[s] == '/') + s++; + name_prefix = name_prefix.substr(s, e-s); + if (name_prefix.size()) + name_prefix += "/"; + } + // Create client + ringloop = new ring_loop_t(512); + epmgr = new epoll_manager_t(ringloop); + cli = new cluster_client_t(ringloop, epmgr->tfd, cfg); + cmd = new cli_tool_t(); + cmd->ringloop = ringloop; + cmd->epmgr = epmgr; + cmd->cli = cli; + // We need inode name hashes for NFS handles to remain stateless and <= 64 bytes long + dir_info[""] = (nfs_dir_t){ + .id = 1, + .mod_rev = 0, + }; + clock_gettime(CLOCK_REALTIME, &dir_info[""].mtime); + watch_stats(); + assert(cli->st_cli.on_inode_change_hook == NULL); + cli->st_cli.on_inode_change_hook = [this](inode_t changed_inode, bool removed) + { + auto inode_cfg_it = cli->st_cli.inode_config.find(changed_inode); + if (inode_cfg_it == cli->st_cli.inode_config.end()) + { + return; + } + auto & inode_cfg = inode_cfg_it->second; + std::string full_name = inode_cfg.name; + if (name_prefix != "" && full_name.substr(0, name_prefix.size()) != name_prefix) + { + return; + } + // Calculate directory modification time and revision (used as "cookie verifier") + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + dir_info[""].mod_rev = dir_info[""].mod_rev < inode_cfg.mod_revision ? inode_cfg.mod_revision : dir_info[""].mod_rev; + dir_info[""].mtime = now; + int pos = full_name.find('/', name_prefix.size()); + while (pos >= 0) + { + std::string dir = full_name.substr(0, pos); + auto & dinf = dir_info[dir]; + if (!dinf.id) + dinf.id = next_dir_id++; + dinf.mod_rev = dinf.mod_rev < inode_cfg.mod_revision ? inode_cfg.mod_revision : dinf.mod_rev; + dinf.mtime = now; + dir_by_hash["S"+base64_encode(sha256(dir))] = dir; + pos = full_name.find('/', pos+1); + } + // Alter inode_by_hash + if (removed) + { + auto ino_it = hash_by_inode.find(changed_inode); + if (ino_it != hash_by_inode.end()) + { + inode_by_hash.erase(ino_it->second); + hash_by_inode.erase(ino_it); + } + } + else + { + std::string hash = "S"+base64_encode(sha256(full_name)); + auto hbi_it = hash_by_inode.find(changed_inode); + if (hbi_it != hash_by_inode.end() && hbi_it->second != hash) + { + // inode had a different name, remove old hash=>inode pointer + inode_by_hash.erase(hbi_it->second); + } + inode_by_hash[hash] = changed_inode; + hash_by_inode[changed_inode] = hash; + } + }; + // Load image metadata + while (!cli->is_ready()) + { + ringloop->loop(); + if (cli->is_ready()) + break; + ringloop->wait(); + } + // Check default pool + check_default_pool(); + // Self-register portmap and NFS + pmap.reg_ports.insert((portmap_id_t){ + .prog = PMAP_PROGRAM, + .vers = PMAP_V2, + .port = portmap_enabled ? 111 : nfs_port, + .owner = "portmapper-service", + .addr = portmap_enabled ? "0.0.0.0.0.111" : ("0.0.0.0.0."+std::to_string(nfs_port)), + }); + pmap.reg_ports.insert((portmap_id_t){ + .prog = PMAP_PROGRAM, + .vers = PMAP_V3, + .port = portmap_enabled ? 111 : nfs_port, + .owner = "portmapper-service", + .addr = portmap_enabled ? "0.0.0.0.0.111" : ("0.0.0.0.0."+std::to_string(nfs_port)), + }); + pmap.reg_ports.insert((portmap_id_t){ + .prog = NFS_PROGRAM, + .vers = NFS_V3, + .port = nfs_port, + .owner = "nfs-server", + .addr = "0.0.0.0.0."+std::to_string(nfs_port), + }); + pmap.reg_ports.insert((portmap_id_t){ + .prog = MOUNT_PROGRAM, + .vers = MOUNT_V3, + .port = nfs_port, + .owner = "rpc.mountd", + .addr = "0.0.0.0.0."+std::to_string(nfs_port), + }); + // Create NFS socket and add it to epoll + int nfs_socket = create_and_bind_socket(bind_address, nfs_port, 128, NULL); + fcntl(nfs_socket, F_SETFL, fcntl(nfs_socket, F_GETFL, 0) | O_NONBLOCK); + epmgr->tfd->set_fd_handler(nfs_socket, false, [this](int nfs_socket, int epoll_events) + { + if (epoll_events & EPOLLRDHUP) + { + fprintf(stderr, "Listening portmap socket disconnected, exiting\n"); + exit(1); + } + else + { + do_accept(nfs_socket); + } + }); + if (portmap_enabled) + { + // Create portmap socket and add it to epoll + int portmap_socket = create_and_bind_socket(bind_address, 111, 128, NULL); + fcntl(portmap_socket, F_SETFL, fcntl(portmap_socket, F_GETFL, 0) | O_NONBLOCK); + epmgr->tfd->set_fd_handler(portmap_socket, false, [this](int portmap_socket, int epoll_events) + { + if (epoll_events & EPOLLRDHUP) + { + fprintf(stderr, "Listening portmap socket disconnected, exiting\n"); + exit(1); + } + else + { + do_accept(portmap_socket); + } + }); + } + if (cfg["foreground"].is_null()) + { + daemonize(); + } + while (true) + { + ringloop->loop(); + ringloop->wait(); + } + /*// Sync at the end + cluster_op_t *close_sync = new cluster_op_t; + close_sync->opcode = OSD_OP_SYNC; + close_sync->callback = [&stop](cluster_op_t *op) + { + stop = true; + delete op; + }; + cli->execute(close_sync);*/ + // Destroy the client + delete cli; + delete epmgr; + delete ringloop; + cli = NULL; + epmgr = NULL; + ringloop = NULL; +} + +void nfs_proxy_t::watch_stats() +{ + assert(cli->st_cli.on_start_watcher_hook == NULL); + cli->st_cli.on_start_watcher_hook = [this](http_co_t *etcd_watch_ws) + { + http_post_message(etcd_watch_ws, WS_TEXT, json11::Json(json11::Json::object { + { "create_request", json11::Json::object { + { "key", base64_encode(cli->st_cli.etcd_prefix+"/inode/stats/") }, + { "range_end", base64_encode(cli->st_cli.etcd_prefix+"/inode/stats0") }, + { "start_revision", cli->st_cli.etcd_watch_revision }, + { "watch_id", ETCD_INODE_STATS_WATCH_ID }, + { "progress_notify", true }, + } } + }).dump()); + http_post_message(etcd_watch_ws, WS_TEXT, json11::Json(json11::Json::object { + { "create_request", json11::Json::object { + { "key", base64_encode(cli->st_cli.etcd_prefix+"/pool/stats/") }, + { "range_end", base64_encode(cli->st_cli.etcd_prefix+"/pool/stats0") }, + { "start_revision", cli->st_cli.etcd_watch_revision }, + { "watch_id", ETCD_POOL_STATS_WATCH_ID }, + { "progress_notify", true }, + } } + }).dump()); + cli->st_cli.etcd_txn_slow(json11::Json::object { + { "success", json11::Json::array { + json11::Json::object { + { "request_range", json11::Json::object { + { "key", base64_encode(cli->st_cli.etcd_prefix+"/inode/stats/") }, + { "range_end", base64_encode(cli->st_cli.etcd_prefix+"/inode/stats0") }, + } } + }, + json11::Json::object { + { "request_range", json11::Json::object { + { "key", base64_encode(cli->st_cli.etcd_prefix+"/pool/stats/") }, + { "range_end", base64_encode(cli->st_cli.etcd_prefix+"/pool/stats0") }, + } } + }, + } }, + }, [this](std::string err, json11::Json res) + { + for (auto & rsp: res["responses"].array_items()) + { + for (auto & item: rsp["response_range"]["kvs"].array_items()) + { + etcd_kv_t kv = cli->st_cli.parse_etcd_kv(item); + parse_stats(kv); + } + } + }); + }; + cli->st_cli.on_change_hook = [this, old_hook = cli->st_cli.on_change_hook](std::map & changes) + { + for (auto & p: changes) + { + parse_stats(p.second); + } + }; +} + +void nfs_proxy_t::parse_stats(etcd_kv_t & kv) +{ + auto & key = kv.key; + if (key.substr(0, cli->st_cli.etcd_prefix.length()+13) == cli->st_cli.etcd_prefix+"/inode/stats/") + { + pool_id_t pool_id = 0; + inode_t inode_num = 0; + char null_byte = 0; + sscanf(key.c_str() + cli->st_cli.etcd_prefix.length()+13, "%u/%lu%c", &pool_id, &inode_num, &null_byte); + if (!pool_id || pool_id >= POOL_ID_MAX || !inode_num || null_byte != 0) + { + fprintf(stderr, "Bad etcd key %s, ignoring\n", key.c_str()); + } + else + { + inode_stats[INODE_WITH_POOL(pool_id, inode_num)] = kv.value; + } + } + else if (key.substr(0, cli->st_cli.etcd_prefix.length()+12) == cli->st_cli.etcd_prefix+"/pool/stats/") + { + pool_id_t pool_id = 0; + char null_byte = 0; + sscanf(key.c_str() + cli->st_cli.etcd_prefix.length()+12, "%u%c", &pool_id, &null_byte); + if (!pool_id || pool_id >= POOL_ID_MAX) + { + fprintf(stderr, "Bad etcd key %s, ignoring\n", key.c_str()); + } + else + { + pool_stats[pool_id] = kv.value; + } + } +} + +void nfs_proxy_t::check_default_pool() +{ + if (default_pool == "") + { + if (cli->st_cli.pool_config.size() == 1) + { + default_pool = cli->st_cli.pool_config.begin()->second.name; + default_pool_id = cli->st_cli.pool_config.begin()->first; + } + else + { + fprintf(stderr, "There are %lu pools. Please select default pool with --pool option\n", cli->st_cli.pool_config.size()); + exit(1); + } + } + else + { + for (auto & p: cli->st_cli.pool_config) + { + if (p.second.name == default_pool) + { + default_pool_id = p.first; + break; + } + } + if (!default_pool_id) + { + fprintf(stderr, "Pool %s is not found\n", default_pool.c_str()); + exit(1); + } + } +} + +void nfs_proxy_t::do_accept(int listen_fd) +{ + struct sockaddr_storage addr; + socklen_t addr_size = sizeof(addr); + int nfs_fd = 0; + while ((nfs_fd = accept(listen_fd, (struct sockaddr *)&addr, &addr_size)) >= 0) + { + fprintf(stderr, "New client %d: connection from %s\n", nfs_fd, addr_to_string(addr).c_str()); + fcntl(nfs_fd, F_SETFL, fcntl(nfs_fd, F_GETFL, 0) | O_NONBLOCK); + int one = 1; + setsockopt(nfs_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); + auto cli = new nfs_client_t(); + cli->parent = this; + cli->nfs_fd = nfs_fd; + for (auto & fn: pmap.proc_table) + { + cli->proc_table.insert(fn); + } + epmgr->tfd->set_fd_handler(nfs_fd, true, [cli](int nfs_fd, int epoll_events) + { + // Handle incoming event + if (epoll_events & EPOLLRDHUP) + { + fprintf(stderr, "Client %d disconnected\n", nfs_fd); + cli->stop(); + return; + } + cli->epoll_events |= epoll_events; + if (epoll_events & EPOLLIN) + { + // Something is available for reading + cli->submit_read(0); + } + if (epoll_events & EPOLLOUT) + { + cli->submit_send(); + } + }); + } + if (nfs_fd < 0 && errno != EAGAIN) + { + fprintf(stderr, "Failed to accept connection: %s\n", strerror(errno)); + exit(1); + } +} + +// FIXME Move these functions to "rpc_context" +void nfs_client_t::select_read_buffer(unsigned wanted_size) +{ + if (free_buffers.size()) + { + auto & b = free_buffers.back(); + if (b.size < wanted_size) + { + cur_buffer = { + .buf = (uint8_t*)malloc_or_die(wanted_size), + .size = wanted_size, + }; + } + else + { + cur_buffer = { + .buf = b.buf, + .size = b.size, + }; + } + free_buffers.pop_back(); + } + else + { + unsigned sz = RPC_INIT_BUF_SIZE; + if (sz < wanted_size) + { + sz = wanted_size; + } + cur_buffer = { + .buf = (uint8_t*)malloc_or_die(sz), + .size = sz, + }; + } +} + +void nfs_client_t::submit_read(unsigned wanted_size) +{ + if (read_msg.msg_iovlen) + { + return; + } + io_uring_sqe* sqe = parent->ringloop->get_sqe(); + if (!sqe) + { + read_msg.msg_iovlen = 0; + parent->ringloop->wakeup(); + return; + } + if (!cur_buffer.buf || cur_buffer.size <= cur_buffer.read_pos) + { + assert(!wanted_size); + if (cur_buffer.buf) + { + if (cur_buffer.refs > 0) + { + used_buffers[cur_buffer.buf] = (rpc_used_buffer_t){ + .size = cur_buffer.size, + .refs = cur_buffer.refs, + }; + } + else + { + free_buffers.push_back((rpc_free_buffer_t){ + .buf = cur_buffer.buf, + .size = cur_buffer.size, + }); + } + } + select_read_buffer(wanted_size); + } + assert(wanted_size <= cur_buffer.size-cur_buffer.read_pos); + read_iov = { + .iov_base = cur_buffer.buf+cur_buffer.read_pos, + .iov_len = wanted_size ? wanted_size : cur_buffer.size-cur_buffer.read_pos, + }; + read_msg.msg_iov = &read_iov; + read_msg.msg_iovlen = 1; + ring_data_t* data = ((ring_data_t*)sqe->user_data); + data->callback = [this](ring_data_t *data) { handle_read(data->res); }; + my_uring_prep_recvmsg(sqe, nfs_fd, &read_msg, 0); + refs++; +} + +void nfs_client_t::handle_read(int result) +{ + read_msg.msg_iovlen = 0; + if (deref()) + return; + if (result <= 0 && result != -EAGAIN && result != -EINTR) + { + printf("Failed read from client %d: %d (%s)\n", nfs_fd, result, strerror(-result)); + stop(); + return; + } + if (result > 0) + { + cur_buffer.read_pos += result; + assert(cur_buffer.read_pos <= cur_buffer.size); + // Try to parse incoming RPC messages + uint8_t *data = cur_buffer.buf + cur_buffer.parsed_pos; + unsigned left = cur_buffer.read_pos - cur_buffer.parsed_pos; + while (left > 0) + { + // Assemble all fragments + unsigned fragments = 0; + uint32_t wanted = 0; + while (1) + { + fragments++; + wanted += 4; + if (left < wanted) + { + break; + } + // FIXME: Limit message size + uint32_t frag_size = be32toh(*(uint32_t*)(data + wanted - 4)); + wanted += (frag_size & 0x7FFFFFFF); + if (left < wanted || (frag_size & 0x80000000)) + { + break; + } + } + if (left >= wanted) + { + if (fragments > 1) + { + // Merge fragments. Fragmented messages are probably not that common, + // so it's probably fine to do an additional memory copy + unsigned frag_offset = 8+be32toh(*(uint32_t*)(data)); + unsigned dest_offset = 4+be32toh(*(uint32_t*)(data)); + unsigned frag_num = 1; + while (frag_num < fragments) + { + uint32_t frag_size = be32toh(*(uint32_t*)(data + frag_offset - 4)) & 0x7FFFFFFF; + memmove(data + dest_offset, data + frag_offset, frag_size); + frag_offset += 4+frag_size; + dest_offset += frag_size; + frag_num++; + } + } + // Handle full message + int referenced = handle_rpc_message(cur_buffer.buf, data+4, wanted-4*fragments); + cur_buffer.refs += referenced ? 1 : 0; + cur_buffer.parsed_pos += 4+wanted-4*fragments; + data += wanted; + left -= wanted; + } + else if (cur_buffer.size >= (data - cur_buffer.buf + wanted)) + { + // Read the tail and come back + submit_read(wanted-left); + break; + } + else + { + // No place to put the whole tail + if (cur_buffer.refs > 0) + { + used_buffers[cur_buffer.buf] = (rpc_used_buffer_t){ + .size = cur_buffer.size, + .refs = cur_buffer.refs, + }; + select_read_buffer(wanted); + memcpy(cur_buffer.buf, data, left); + } + else if (cur_buffer.size < wanted) + { + uint8_t *old_buf = cur_buffer.buf; + select_read_buffer(wanted); + memcpy(cur_buffer.buf, data, left); + free(old_buf); + } + else + { + memmove(cur_buffer.buf, data, left); + } + cur_buffer.read_pos = left; + cur_buffer.parsed_pos = 0; + // Restart from the beginning + submit_read(wanted-left); + break; + } + } + } +} + +void nfs_client_t::submit_send() +{ + if (write_msg.msg_iovlen || !send_list.size()) + { + return; + } + io_uring_sqe* sqe = parent->ringloop->get_sqe(); + if (!sqe) + { + write_msg.msg_iovlen = 0; + parent->ringloop->wakeup(); + return; + } + write_msg.msg_iov = send_list.data(); + write_msg.msg_iovlen = send_list.size() < IOV_MAX ? send_list.size() : IOV_MAX; + ring_data_t* data = ((ring_data_t*)sqe->user_data); + data->callback = [this](ring_data_t *data) { handle_send(data->res); }; + my_uring_prep_sendmsg(sqe, nfs_fd, &write_msg, 0); + refs++; +} + +bool nfs_client_t::deref() +{ + refs--; + if (stopped && refs <= 0) + { + stop(); + return true; + } + return false; +} + +void nfs_client_t::stop() +{ + stopped = true; + if (refs <= 0) + { + parent->epmgr->tfd->set_fd_handler(nfs_fd, true, NULL); + close(nfs_fd); + delete this; + } +} + +void nfs_client_t::handle_send(int result) +{ + write_msg.msg_iovlen = 0; + if (deref()) + return; + if (result <= 0 && result != -EAGAIN && result != -EINTR) + { + printf("Failed send to client %d: %d (%s)\n", nfs_fd, result, strerror(-result)); + stop(); + return; + } + if (result > 0) + { + int done = 0; + while (result > 0 && done < send_list.size()) + { + iovec & iov = send_list[done]; + if (iov.iov_len <= result) + { + auto rop = outbox[done]; + if (rop) + { + // Reply fully sent + xdr_reset(rop->xdrs); + parent->xdr_pool.push_back(rop->xdrs); + if (rop->buffer && rop->referenced) + { + // Dereference the buffer + if (rop->buffer == cur_buffer.buf) + { + cur_buffer.refs--; + } + else + { + auto & ub = used_buffers.at(rop->buffer); + assert(ub.refs > 0); + ub.refs--; + if (ub.refs == 0) + { + // FIXME Maybe put free_buffers into parent + free_buffers.push_back((rpc_free_buffer_t){ + .buf = rop->buffer, + .size = ub.size, + }); + used_buffers.erase(rop->buffer); + } + } + } + free(rop); + } + result -= iov.iov_len; + done++; + } + else + { + iov.iov_len -= result; + iov.iov_base = (uint8_t*)iov.iov_base + result; + break; + } + } + if (done > 0) + { + send_list.erase(send_list.begin(), send_list.begin()+done); + outbox.erase(outbox.begin(), outbox.begin()+done); + } + if (next_send_list.size()) + { + send_list.insert(send_list.end(), next_send_list.begin(), next_send_list.end()); + outbox.insert(outbox.end(), next_outbox.begin(), next_outbox.end()); + next_send_list.clear(); + next_outbox.clear(); + } + if (outbox.size() > 0) + { + submit_send(); + } + } +} + +void rpc_queue_reply(rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)rop->client; + iovec *iov_list = NULL; + unsigned iov_count = 0; + int r = xdr_encode(rop->xdrs, (xdrproc_t)xdr_rpc_msg, &rop->out_msg); + assert(r); + if (rop->reply_fn != NULL) + { + r = xdr_encode(rop->xdrs, rop->reply_fn, rop->reply); + assert(r); + } + xdr_encode_finish(rop->xdrs, &iov_list, &iov_count); + assert(iov_count > 0); + rop->reply_marker = 0; + for (unsigned i = 0; i < iov_count; i++) + { + rop->reply_marker += iov_list[i].iov_len; + } + rop->reply_marker = htobe32(rop->reply_marker | 0x80000000); + auto & to_send_list = self->write_msg.msg_iovlen ? self->next_send_list : self->send_list; + auto & to_outbox = self->write_msg.msg_iovlen ? self->next_outbox : self->outbox; + to_send_list.push_back((iovec){ .iov_base = &rop->reply_marker, .iov_len = 4 }); + to_outbox.push_back(NULL); + for (unsigned i = 0; i < iov_count; i++) + { + to_send_list.push_back(iov_list[i]); + to_outbox.push_back(NULL); + } + to_outbox[to_outbox.size()-1] = rop; + self->submit_send(); +} + +int nfs_client_t::handle_rpc_message(void *base_buf, void *msg_buf, uint32_t msg_len) +{ + // Take an XDR object from the pool + XDR *xdrs; + if (parent->xdr_pool.size()) + { + xdrs = parent->xdr_pool.back(); + parent->xdr_pool.pop_back(); + } + else + { + xdrs = xdr_create(); + } + // Decode the RPC header + char inmsg_data[sizeof(rpc_msg)]; + rpc_msg *inmsg = (rpc_msg*)&inmsg_data; + if (!xdr_decode(xdrs, msg_buf, msg_len, (xdrproc_t)xdr_rpc_msg, inmsg)) + { + // Invalid message, ignore it + xdr_reset(xdrs); + parent->xdr_pool.push_back(xdrs); + return 0; + } + if (inmsg->body.dir != RPC_CALL) + { + // Reply sent to the server? Strange thing. Also ignore it + xdr_reset(xdrs); + parent->xdr_pool.push_back(xdrs); + return 0; + } + if (inmsg->body.cbody.rpcvers != RPC_MSG_VERSION) + { + // Bad RPC version + rpc_op_t *rop = (rpc_op_t*)malloc(sizeof(rpc_op_t)); + *rop = { + .client = this, + .xdrs = xdrs, + .out_msg = (rpc_msg){ + .xid = inmsg->xid, + .body = (rpc_msg_body){ + .dir = RPC_REPLY, + .rbody = (rpc_reply_body){ + .stat = RPC_MSG_DENIED, + .rreply = (rpc_rejected_reply){ + .stat = RPC_MISMATCH, + .mismatch_info = (rpc_mismatch_info){ + .min_version = RPC_MSG_VERSION, + .max_version = RPC_MSG_VERSION, + }, + }, + }, + }, + }, + }; + rpc_queue_reply(rop); + // Incoming buffer isn't needed to handle request, so return 0 + return 0; + } + // Find decoder for the request + auto proc_it = proc_table.find((rpc_service_proc_t){ + .prog = inmsg->body.cbody.prog, + .vers = inmsg->body.cbody.vers, + .proc = inmsg->body.cbody.proc, + }); + if (proc_it == proc_table.end()) + { + // Procedure not implemented + uint32_t min_vers = 0, max_vers = 0; + auto prog_it = proc_table.lower_bound((rpc_service_proc_t){ + .prog = inmsg->body.cbody.prog, + }); + if (prog_it != proc_table.end()) + { + min_vers = prog_it->vers; + auto max_vers_it = proc_table.lower_bound((rpc_service_proc_t){ + .prog = inmsg->body.cbody.prog+1, + }); + assert(max_vers_it != proc_table.begin()); + max_vers_it--; + assert(max_vers_it->prog == inmsg->body.cbody.prog); + max_vers = max_vers_it->vers; + } + rpc_op_t *rop = (rpc_op_t*)malloc_or_die(sizeof(rpc_op_t)); + *rop = { + .client = this, + .xdrs = xdrs, + .out_msg = (rpc_msg){ + .xid = inmsg->xid, + .body = (rpc_msg_body){ + .dir = RPC_REPLY, + .rbody = (rpc_reply_body){ + .stat = RPC_MSG_ACCEPTED, + .areply = (rpc_accepted_reply){ + .reply_data = (rpc_accepted_reply_body){ + .stat = (min_vers == 0 + ? RPC_PROG_UNAVAIL + : (min_vers <= inmsg->body.cbody.vers && + max_vers >= inmsg->body.cbody.vers + ? RPC_PROC_UNAVAIL + : RPC_PROG_MISMATCH)), + .mismatch_info = (rpc_mismatch_info){ .min_version = min_vers, .max_version = max_vers }, + }, + }, + }, + }, + }, + }; + rpc_queue_reply(rop); + // Incoming buffer isn't needed to handle request, so return 0 + return 0; + } + // Allocate memory + rpc_op_t *rop = (rpc_op_t*)malloc_or_die( + sizeof(rpc_op_t) + proc_it->req_size + proc_it->resp_size + ); + *rop = (rpc_op_t){ + .client = this, + .buffer = (uint8_t*)base_buf, + .xdrs = xdrs, + .out_msg = (rpc_msg){ + .xid = inmsg->xid, + .body = (rpc_msg_body){ + .dir = RPC_REPLY, + .rbody = (rpc_reply_body){ + .stat = RPC_MSG_ACCEPTED, + }, + }, + }, + .request = ((uint8_t*)rop) + sizeof(rpc_op_t), + .reply = ((uint8_t*)rop) + sizeof(rpc_op_t) + proc_it->req_size, + }; + memcpy(&rop->in_msg, inmsg, sizeof(rpc_msg)); + // Try to decode the request + // req_fn may be NULL, that means function has no arguments + if (proc_it->req_fn && !proc_it->req_fn(xdrs, rop->request)) + { + // Invalid request + rop->out_msg.body.rbody.areply.reply_data.stat = RPC_GARBAGE_ARGS; + rpc_queue_reply(rop); + // Incoming buffer isn't needed to handle request, so return 0 + return 0; + } + rop->out_msg.body.rbody.areply.reply_data.stat = RPC_SUCCESS; + rop->reply_fn = proc_it->resp_fn; + int ref = proc_it->handler_fn(proc_it->opaque, rop); + rop->referenced = ref ? 1 : 0; + return ref; +} + +void nfs_proxy_t::daemonize() +{ + if (fork()) + exit(0); + setsid(); + if (fork()) + exit(0); + if (chdir("/") != 0) + fprintf(stderr, "Warning: Failed to chdir into /\n"); + close(0); + close(1); + close(2); + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); +} + +int main(int narg, const char *args[]) +{ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + exe_name = args[0]; + nfs_proxy_t *p = new nfs_proxy_t(); + p->run(nfs_proxy_t::parse_args(narg, args)); + delete p; + return 0; +} diff --git a/src/nfs_proxy.h b/src/nfs_proxy.h new file mode 100644 index 000000000..951f22ba7 --- /dev/null +++ b/src/nfs_proxy.h @@ -0,0 +1,124 @@ +#pragma once + +#include "cluster_client.h" +#include "epoll_manager.h" +#include "nfs_portmap.h" +#include "nfs/xdr_impl.h" + +#define RPC_INIT_BUF_SIZE 32768 + +class cli_tool_t; + +struct nfs_dir_t +{ + uint64_t id; + uint64_t mod_rev; + timespec mtime; +}; + +class nfs_proxy_t +{ +public: + std::string bind_address; + std::string name_prefix; + uint64_t fsid = 1; + uint64_t server_id = 0; + std::string default_pool; + std::string export_root; + bool portmap_enabled; + unsigned nfs_port; + + pool_id_t default_pool_id; + + portmap_service_t pmap; + ring_loop_t *ringloop = NULL; + epoll_manager_t *epmgr = NULL; + cluster_client_t *cli = NULL; + cli_tool_t *cmd = NULL; + + std::vector xdr_pool; + + // filehandle = "S"+base64(sha256(full name with prefix)) or "roothandle" for mount root) + + uint64_t next_dir_id = 2; + // filehandle => dir with name_prefix + std::map dir_by_hash; + // dir with name_prefix => dir info + std::map dir_info; + // filehandle => inode ID + std::map inode_by_hash; + // inode ID => filehandle + std::map hash_by_inode; + // inode ID => statistics + std::map inode_stats; + // pool ID => statistics + std::map pool_stats; + + ~nfs_proxy_t(); + + static json11::Json::object parse_args(int narg, const char *args[]); + void run(json11::Json cfg); + void watch_stats(); + void parse_stats(etcd_kv_t & kv); + void check_default_pool(); + void do_accept(int listen_fd); + void daemonize(); +}; + +struct rpc_cur_buffer_t +{ + uint8_t *buf; + unsigned size; + unsigned read_pos; + unsigned parsed_pos; + int refs; +}; + +struct rpc_used_buffer_t +{ + unsigned size; + int refs; +}; + +struct rpc_free_buffer_t +{ + uint8_t *buf; + unsigned size; +}; + +class nfs_client_t +{ +public: + nfs_proxy_t *parent = NULL; + int nfs_fd; + int epoll_events = 0; + int refs = 0; + bool stopped = false; + std::set proc_table; + + // Read state + rpc_cur_buffer_t cur_buffer = { 0 }; + std::map used_buffers; + std::vector free_buffers; + + iovec read_iov; + msghdr read_msg = { 0 }; + + // Write state + msghdr write_msg = { 0 }; + std::vector send_list, next_send_list; + std::vector outbox, next_outbox; + + nfs_client_t(); + ~nfs_client_t(); + + void select_read_buffer(unsigned wanted_size); + void submit_read(unsigned wanted_size); + void handle_read(int result); + void submit_send(); + void handle_send(int result); + int handle_rpc_message(void *base_buf, void *msg_buf, uint32_t msg_len); + + bool deref(); + void stop(); +}; diff --git a/src/sha256.c b/src/sha256.c new file mode 100644 index 000000000..eb9c5c073 --- /dev/null +++ b/src/sha256.c @@ -0,0 +1,158 @@ +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include +#include +#include "sha256.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void sha256_init(SHA256_CTX *ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) +{ + WORD i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void sha256_final(SHA256_CTX *ctx, BYTE hash[]) +{ + WORD i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} diff --git a/src/sha256.h b/src/sha256.h new file mode 100644 index 000000000..17987c625 --- /dev/null +++ b/src/sha256.h @@ -0,0 +1,41 @@ +/********************************************************************* +* Filename: sha256.h +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Defines the API for the corresponding SHA1 implementation. +*********************************************************************/ + +#ifndef SHA256_H +#define SHA256_H + +/*************************** HEADER FILES ***************************/ +#include + +/****************************** MACROS ******************************/ +#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest + +#ifdef __cplusplus +extern "C" { +#endif +/**************************** DATA TYPES ****************************/ +typedef unsigned char BYTE; // 8-bit byte +typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[8]; +} SHA256_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ +void sha256_init(SHA256_CTX *ctx); +void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); +void sha256_final(SHA256_CTX *ctx, BYTE hash[]); + +#ifdef __cplusplus +}; +#endif + +#endif // SHA256_H