/* * linux/net/sunrpc/xdr.c * * Generic XDR support. * * Copyright (C) 1995, 1996 Olaf Kirch */ #include #include #include #include #include #include #include /* * XDR functions for basic NFS types */ u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj) { unsigned int quadlen = XDR_QUADLEN(obj->len); p[quadlen] = 0; /* zero trailing bytes */ *p++ = htonl(obj->len); memcpy(p, obj->data, obj->len); return p + XDR_QUADLEN(obj->len); } u32 * xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len) { if (ntohl(*p++) != len) return NULL; memcpy(obj, p, len); return p + XDR_QUADLEN(len); } u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *obj) { unsigned int len; if ((len = ntohl(*p++)) > XDR_MAX_NETOBJ) return NULL; obj->len = len; obj->data = (u8 *) p; return p + XDR_QUADLEN(len); } u32 * xdr_encode_array(u32 *p, const char *array, unsigned int len) { int quadlen = XDR_QUADLEN(len); p[quadlen] = 0; *p++ = htonl(len); memcpy(p, array, len); return p + quadlen; } u32 * xdr_encode_string(u32 *p, const char *string) { return xdr_encode_array(p, string, strlen(string)); } u32 * xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen) { unsigned int len; char *string; if ((len = ntohl(*p++)) > maxlen) return NULL; if (lenp) *lenp = len; if ((len % 4) != 0) { string = (char *) p; } else { string = (char *) (p - 1); memmove(string, p, len); } string[len] = '\0'; *sp = string; return p + XDR_QUADLEN(len); } u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen) { unsigned int len; if ((len = ntohl(*p++)) > maxlen) return NULL; *lenp = len; *sp = (char *) p; return p + XDR_QUADLEN(len); } /* * Realign the iovec if the server missed out some reply elements * (such as post-op attributes,...) * Note: This is a simple implementation that assumes that * len <= iov->iov_len !!! * The RPC header (assumed to be the 1st element in the iov array) * is not shifted. */ void xdr_shift_iovec(struct iovec *iov, int nr, size_t len) { struct iovec *pvec; for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) { struct iovec *svec = pvec - 1; if (len > pvec->iov_len) { printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n"); return; } memmove((char *)pvec->iov_base + len, pvec->iov_base, pvec->iov_len - len); if (len > svec->iov_len) { printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n"); return; } memcpy(pvec->iov_base, (char *)svec->iov_base + svec->iov_len - len, len); } } /* * Zero the last n bytes in an iovec array of 'nr' elements */ void xdr_zero_iovec(struct iovec *iov, int nr, size_t n) { struct iovec *pvec; for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) { if (n < pvec->iov_len) { memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n); n = 0; } else { memset(pvec->iov_base, 0, pvec->iov_len); n -= pvec->iov_len; } } }