/*
 * $Id: xdr.c,v 1.9 2006/06/14 10:50:49 c4chris Exp $
 */

#include "os.h"

/*
 * xdr.c - XDR routines for decoding NFS packets.
 *
 * David A. Curry				Jeffrey C. Mogul
 * Purdue University				Digital Equipment Corporation
 * Engineering Computer Network			Western Research Laboratory
 * 1285 Electrical Engineering Building		250 University Avenue
 * West Lafayette, IN 47907-1285		Palo Alto, CA 94301
 * davy@ecn.purdue.edu				mogul@decwrl.dec.com
 * 
 */
#include <sys/param.h>
#include <netinet/in.h>
#ifdef SVR4
#include <sys/tiuser.h>
#endif
#ifdef USE_LINUX
/* This yucky hack is needed because glibc's headers are wrong wrt the
 * correct size needed in RPC stuff on 64-bit machines.  There even is
 * a comment in <rpc/types.h> to that effect...  */
#define u_long uint32_t
#endif
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#include <rpc/rpc_msg.h>
#include <rpc/svc.h>
#ifdef USE_LINUX
#undef u_long
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#define NFSSERVER	1

#ifdef sun
#include <sys/vfs.h>
#include <nfs/nfs.h>
#endif

#ifdef ultrix
#include <sys/types.h>
#include <sys/time.h>
#include <nfs/nfs.h>
#endif

#ifdef sgi
#include <sys/time.h>
#ifdef IRIX6
#include <sys/vfs.h>
#include <sys/fs/nfs.h>
#else
#include "sgi.map.h"
#endif
#endif

#ifdef __osf__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <nfs/nfs.h>
#endif

#ifdef LINUX
#include "linux.map.h"
#endif

#include "nfswatch.h"
#include "rpcdefs.h"

bool_t
xdr_creatargs(XDR *xdrs, struct nfscreatargs *argp)
{
#if defined(SUNOS5) && defined(DA_FREENAME)     /* SunOS 2.2 and greater */
	argp->ca_sa = &argp->ca_sa_buf;

	if (xdr_diropargs(xdrs, &argp->ca_da) &&
	    xdr_sattr(xdrs, &argp->ca_sa_buf))
		return(TRUE);
#else
	if (xdr_diropargs(xdrs, &argp->ca_da) &&
	    xdr_sattr(xdrs, &argp->ca_sa))
		return(TRUE);
#endif

	return(FALSE);
}

bool_t
xdr_diropargs(XDR *xdrs, struct nfsdiropargs *argp)
{
#if defined(SUNOS5) && defined(DA_FREENAME)     /* SunOS 2.2 and greater */
	argp->da_fhandle = &argp->da_fhandle_buf;

	if (xdr_fhandle(xdrs, &argp->da_fhandle_buf) &&
	    xdr_string(xdrs, &argp->da_name, NFS_MAXNAMLEN)) {
		free(argp->da_name);
		return(TRUE);
	}
#else
	if (xdr_fhandle(xdrs, &argp->da_fhandle) &&
	    xdr_string(xdrs, &argp->da_name, NFS_MAXNAMLEN)) {
		free(argp->da_name);
		return(TRUE);
	}
#endif

	return(FALSE);
}

bool_t
xdr_fhandle(XDR *xdrs, fhandle_t *argp)
{
	if (xdr_opaque(xdrs, (caddr_t) argp, NFS_FHSIZE))
		return(TRUE);

	return(FALSE);
}

bool_t
xdr_linkargs(XDR *xdrs, struct nfslinkargs *argp)
{
#if defined(SUNOS5) && defined(DA_FREENAME)     /* SunOS 2.2 and greater */
	argp->la_from = &argp->la_from_buf;

	if (xdr_fhandle(xdrs, &argp->la_from_buf) &&
	    xdr_diropargs(xdrs, &argp->la_to))
		return(TRUE);
#else
	if (xdr_fhandle(xdrs, &argp->la_from) &&
	    xdr_diropargs(xdrs, &argp->la_to))
		return(TRUE);
#endif

	return(FALSE);
}

bool_t
xdr_rddirargs(XDR *xdrs, struct nfsrddirargs *argp)
{
	if (xdr_fhandle(xdrs, &argp->rda_fh) &&
	    xdr_u_int(xdrs, (u_int32 *)&argp->rda_offset) &&
	    xdr_u_int(xdrs, (u_int32 *)&argp->rda_count))
		return(TRUE);

	return(FALSE);
}

bool_t
xdr_readargs(XDR *xdrs, struct nfsreadargs *argp)
{
	if (xdr_fhandle(xdrs, &argp->ra_fhandle) &&
	    xdr_int(xdrs, (int32 *) &argp->ra_offset) &&
	    xdr_int(xdrs, (int32 *) &argp->ra_count) &&
	    xdr_int(xdrs, (int32 *) &argp->ra_totcount))
		return(TRUE);

	return(FALSE);
}

bool_t
xdr_rnmargs(XDR *xdrs, struct nfsrnmargs *argp)
{
	if (xdr_diropargs(xdrs, &argp->rna_from) &&
	    xdr_diropargs(xdrs, &argp->rna_to))
		return(TRUE);

	return(FALSE);
}

bool_t
xdr_saargs(XDR *xdrs, struct nfssaargs *argp)
{
	if (xdr_fhandle(xdrs, &argp->saa_fh) &&
	    xdr_sattr(xdrs, &argp->saa_sa))
		return(TRUE);

	return(FALSE);
}

bool_t
xdr_sattr(XDR *xdrs, struct nfssattr *argp)
{
	if (xdr_u_int(xdrs, (u_int32 *)&argp->sa_mode) &&
	    xdr_u_int(xdrs, (u_int32 *)&argp->sa_uid) &&
	    xdr_u_int(xdrs, (u_int32 *)&argp->sa_gid) &&
	    xdr_u_int(xdrs, (u_int32 *)&argp->sa_size) &&
	    xdr_nfs2_timeval(xdrs, &argp->sa_atime) &&
	    xdr_nfs2_timeval(xdrs, &argp->sa_mtime))
		return(TRUE);

	return(FALSE);
}

bool_t
xdr_slargs(XDR *xdrs, struct nfsslargs *argp)
{
#if defined(SUNOS5) && defined(DA_FREENAME)     /* SunOS 2.2 and greater */
	argp->sla_sa = &argp->sla_sa_buf;

	if (xdr_diropargs(xdrs, &argp->sla_from) &&
	    xdr_string(xdrs, &argp->sla_tnm, (u_int) MAXPATHLEN) &&
	    xdr_sattr(xdrs, &argp->sla_sa_buf)) {
		free(argp->sla_tnm);
		return(TRUE);
	}
#else
	if (xdr_diropargs(xdrs, &argp->sla_from) &&
	    xdr_string(xdrs, &argp->sla_tnm, (u_int) MAXPATHLEN) &&
	    xdr_sattr(xdrs, &argp->sla_sa)) {
		free(argp->sla_tnm);
		return(TRUE);
	}
#endif

	return(FALSE);
}

bool_t
xdr_nfs2_timeval(XDR *xdrs, struct nfs2_timeval *argp)
{
	if (xdr_int(xdrs, (int32 *)&argp->tv_sec) &&
	    xdr_int(xdrs, (int32 *)&argp->tv_usec))
		return(TRUE);

	return(FALSE);
}

bool_t
xdr_writeargs(XDR *xdrs, struct nfswriteargs *argp)
{
#if defined(SUNOS5) && defined(DA_FREENAME)     /* SunOS 2.2 and greater */
	argp->wa_args = &argp->wa_args_buf;

	if (xdr_fhandle(xdrs, &argp->wa_fhandle) &&
	    xdr_int(xdrs, (int32 *) &argp->wa_begoff) &&
	    xdr_int(xdrs, (int32 *) &argp->wa_offset) &&
	    xdr_int(xdrs, (int32 *) &argp->wa_totcount))
		return(TRUE);
#else
	if (xdr_fhandle(xdrs, &argp->wa_fhandle) &&
	    xdr_int(xdrs, (int32 *) &argp->wa_begoff) &&
	    xdr_int(xdrs, (int32 *) &argp->wa_offset) &&
	    xdr_int(xdrs, (int32 *) &argp->wa_totcount))
		return(TRUE);
#endif

	return(FALSE);
}

bool_t
xdr_nfs_fh3(XDR *xdrs, nfs_fh3 *argp)
{
  if (!xdr_u_int(xdrs, &argp->fh3_length))
    return(FALSE);
  if (argp->fh3_length == NFS_FHSIZE) {
    if (xdr_opaque(xdrs, (caddr_t) &argp->fh3_u.nfs_fh3_i.fh3_i, NFS_FHSIZE))
      return(TRUE);
  } else {
    if (xdr_opaque(xdrs, (caddr_t) argp->fh3_u.data, NFS3_FHSIZE))
      return(TRUE);
  }

  return(FALSE);
}

/* We have at most two diropargs3 as parameters...  */
static char fn3_buf[2][1024];
static int fn3_toggle;

bool_t
xdr_diropargs3(XDR *xdrs, diropargs3 *argp)
{
  fn3_toggle = (fn3_toggle + 1) & 1;
  argp->name = fn3_buf[fn3_toggle];
#if (defined(SUNOS5) && !defined(SUNOS58)) || defined(IRIX6)
  if (xdr_nfs_fh3(xdrs, &argp->dir)
      && xdr_string(xdrs, &argp->name, 1024))
    return(TRUE);
#else
  argp->flags = 0;
  argp->dirp = &argp->dir;
  if (xdr_nfs_fh3(xdrs, argp->dirp)
      && xdr_string(xdrs, &argp->name, 1024))
    return(TRUE);
#endif

  return(FALSE);
}

bool_t
xdr_RENAME3args(XDR *xdrs, RENAME3args *argp)
{
  if (xdr_diropargs3(xdrs, &argp->from)
      && xdr_diropargs3(xdrs, &argp->to))
    return(TRUE);

  return(FALSE);
}

bool_t
xdr_LINK3args(XDR *xdrs, LINK3args *argp)
{
  if (xdr_nfs_fh3(xdrs, &argp->file)
      && xdr_diropargs3(xdrs, &argp->link))
    return(TRUE);

  return(FALSE);
}
