#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif

#define EXPORT_BOOLEAN
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/message.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/mig_errors.h>
#include <mach/mig_support.h>
#include <mach/msg_type.h>

#ifndef	mig_internal
#define	mig_internal	static
#endif

#ifndef	mig_external
#define mig_external
#endif

#ifndef	TypeCheck
#define	TypeCheck 1
#endif

#ifndef	UseExternRCSId
#define	UseExternRCSId		1
#endif

#define BAD_TYPECHECK(type, check) ({\
  union { mach_msg_type_t t; unsigned32_t w; } _t, _c;\
  _t.t = *(type); _c.t = *(check); _t.w != _c.w; })
#define msgh_request_port	msgh_remote_port
#define msgh_reply_port		msgh_local_port

#include <mach/std_types.h>
#include <mach/mach_types.h>
#include <device/device_types.h>
#include <device/net_status.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <hurd/hurd_types.h>

/* Routine dir_lookup */
mig_external kern_return_t xdir_lookup
(
	file_t start_dir,
	int flags,
	mode_t mode,
	retry_type *do_retry,
	string_t retry_name,
	mach_port_t *result
)
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t file_nameType;
		string_t file_name;
		mach_msg_type_t flagsType;
		int flags;
		mach_msg_type_t modeType;
		mode_t mode;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_t do_retryType;
		retry_type do_retry;
		mach_msg_type_t retry_nameType;
		string_t retry_name;
		mach_msg_type_t resultType;
		mach_port_t result;
	} Reply;

	union {
		Request In;
		Reply Out;
	} Mess;

	register Request *InP = &Mess.In;
	register Reply *OutP = &Mess.Out;

	mach_msg_return_t msg_result;
#if	TypeCheck
	boolean_t msgh_simple;
#endif	/* TypeCheck */
#if	TypeCheck
	unsigned int msgh_size;
#endif	/* TypeCheck */

	auto const mach_msg_type_t file_nameType = {
		/* msgt_name = */		MACH_MSG_TYPE_STRING_C,
		/* msgt_size = */		8,
		/* msgt_number = */		1024,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t flagsType = {
		/* msgt_name = */		2,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t modeType = {
		/* msgt_name = */		2,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t RetCodeCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t do_retryCheck = {
		/* msgt_name = */		2,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t retry_nameCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_STRING_C,
		/* msgt_size = */		8,
		/* msgt_number = */		1024,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t resultCheck = {
		/* msgt_name = */		17,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	InP->file_nameType = file_nameType;

	(void) memset(InP->file_name, '!', 1024);

	InP->flagsType = flagsType;

	InP->flags = flags;

	InP->modeType = modeType;

	InP->mode = mode;

	InP->Head.msgh_bits =
		MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
	/* msgh_size passed as argument */
	InP->Head.msgh_request_port = start_dir;
	InP->Head.msgh_reply_port = mig_get_reply_port();
	InP->Head.msgh_seqno = 0;
	InP->Head.msgh_id = 20018;

	msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, 1068, sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
	if (msg_result != MACH_MSG_SUCCESS) {
		mig_dealloc_reply_port(InP->Head.msgh_reply_port);
		return msg_result;
	}
	mig_put_reply_port(InP->Head.msgh_reply_port);

	if (OutP->Head.msgh_id != 20118) {
		if (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
		return MIG_SERVER_DIED;
		else {
			mig_dealloc_reply_port(InP->Head.msgh_reply_port);
			return MIG_REPLY_MISMATCH;
		}
	}

#if	TypeCheck
	msgh_size = OutP->Head.msgh_size;
	msgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);

	if (((msgh_size != 1076) || msgh_simple) &&
	    ((msgh_size != sizeof(mig_reply_header_t)) ||
	     !msgh_simple ||
	     (OutP->RetCode == KERN_SUCCESS)))
		return MIG_TYPE_ERROR;
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK (&OutP->RetCodeType, &RetCodeCheck))
		return MIG_TYPE_ERROR;
#endif	/* TypeCheck */

	if (OutP->RetCode != KERN_SUCCESS)
		return OutP->RetCode;

#if	TypeCheck
	if (BAD_TYPECHECK (&OutP->do_retryType, &do_retryCheck))
		return MIG_TYPE_ERROR;
#endif	/* TypeCheck */

	*do_retry = OutP->do_retry;

#if	TypeCheck
	if (BAD_TYPECHECK (&OutP->retry_nameType, &retry_nameCheck))
		return MIG_TYPE_ERROR;
#endif	/* TypeCheck */

	(void) mig_strncpy(retry_name, OutP->retry_name, 1024);

#if	TypeCheck
	if (BAD_TYPECHECK (&OutP->resultType, &resultCheck))
		return MIG_TYPE_ERROR;
#endif	/* TypeCheck */

	*result = OutP->result;

	return KERN_SUCCESS;
}

#include <hurd.h>
#include <fcntl.h>

int
main (int argc, char *argv[])
{
  mach_port_t dir;
  error_t err;
  retry_type do_retry;
  string_t retry_name;
  mach_port_t result;

  if (argc < 2)
   error (1, 0, "missing file operand");
  
  dir = file_name_lookup (argv[1], 0, O_READ);
  if (dir == MACH_PORT_NULL)
    error (1, errno, "couldn't open file %s", argv[1]);
  err = xdir_lookup (dir, 0, O_READ, &do_retry, retry_name, &result);
  error (1, err, "unterminated filename lookup failed");
  if (do_retry != FS_RETRY_NORMAL)
    error (1, 0, "lookup not complete");

  return 0;
}
