/*
 * $Id: unistd_common_pathconf.c,v 1.4 2008-04-16 07:38:10 obarthel Exp $
 *
 * :ts=4
 *
 * Portable ISO 'C' (1994) runtime library for the Amiga computer
 * Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Neither the name of Olaf Barthel nor the names of contributors
 *     may be used to endorse or promote products derived from this
 *     software without specific prior written permission.
 *
 * 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.
 */

#ifndef _STDLIB_NULL_POINTER_CHECK_H
#include "stdlib_null_pointer_check.h"
#endif /* _STDLIB_NULL_POINTER_CHECK_H */

/****************************************************************************/

#ifndef _UNISTD_HEADERS_H
#include "unistd_headers.h"
#endif /* _UNISTD_HEADERS_H */

/****************************************************************************/

/* The following is not part of the ISO 'C' (1994) standard. */

/****************************************************************************/

#ifndef ID_CON
#define ID_CON (0x434F4E00L) /* 'CON\0' */
#endif /* ID_CON */

#ifndef ID_RAWCON
#define ID_RAWCON (0x52415700L) /* 'RAW\0' */
#endif /* ID_RAWCON */

#ifndef ID_BUSY_DISK
#define ID_BUSY_DISK (0x42555359L) /* 'BUSY' */
#endif /* ID_LONGNAME_DOS_DISK */

#ifndef ID_LONGNAME_DOS_DISK
#define ID_LONGNAME_DOS_DISK (0x444F5306L) /* 'DOS\6' */
#endif /* ID_LONGNAME_DOS_DISK */

#ifndef ID_LONGNAME_FFS_DISK
#define ID_LONGNAME_FFS_DISK (0x444F5307L) /* 'DOS\7' */
#endif /* ID_LONGNAME_FFS_DISK */

/****************************************************************************/

struct fs_info
{
	ULONG	dos_type;
	int		name_max,path_max;
	int		link_max,symlink_max;
	int		file_size_bits;
};

/****************************************************************************/

static const struct fs_info fs_info[] =
{
	{ID_NO_DISK_PRESENT,	0,		0,		0,	0,	0},		/* No disk */
	{ID_UNREADABLE_DISK,	0,		0,		0,	0,	0},		/* BAD\0 */
	{ID_BUSY_DISK,			0,		0,		0,	0,	0},		/* BUSY - Diskchange in progress? */
	{ID_CON,				0,		0,		0,	0,	0},		/* CON\0 - Not really a disk. */
	{ID_RAWCON,				0,		0,		0,	0,	0},		/* RAW\0 - Not really a disk. */
	{ID_NOT_REALLY_DOS,		0,		0,		0,	0,	0},		/* Unreadable disk. */
	{ID_KICKSTART_DISK,		0,		0,		0,	0,	0},		/* Kickstart disk. */
	{ID_MSDOS_DISK,			8,		31,		0,	0,	30},	/* MSDOS - TODO: Check what the limits really are. */
	{ID_DOS_DISK,			30,		254,	-1,	-1,	31},	/* DOS\0 = OFS */
	{ID_FFS_DISK,			30,		254,	-1,	-1,	31},	/* DOS\1 = FFS */
	{ID_INTER_DOS_DISK,		30,		254,	-1,	-1,	31},	/* DOS\2 = OFS INTL */
	{ID_INTER_FFS_DISK,		30,		254,	-1,	-1,	31},	/* DOS\3 = FFS INTL */
	{ID_FASTDIR_DOS_DISK,	30,		254,	-1,	-1,	31},	/* DOS\4 = OFS DC */
	{ID_FASTDIR_FFS_DISK,	30,		254,	-1,	-1,	31},	/* DOS\5 = FFS DC */
	{ID_LONGNAME_DOS_DISK,	107,	8192,	-1,	-1,	31},	/* DOS\6 = OFS LONGNAMES */
	{ID_LONGNAME_FFS_DISK,	107,	8192,	-1,	-1,	63},	/* DOS\7 = FFS LONGNAMES */
	{0x53465300,			107,	8192,	0,	-1,	31},	/* SFS\0 = Smartfilesystem */
	{0x53465302,			107,	8192,	0,	-1,	63},	/* SFS\2 = Smartfilesystem2 */
	{0x50465300,			30,		254,	0,	0,	31},	/* PFS\0 = Professional File System */
	{0x46545854,			0,		0,		0,	0,	0},		/* FTXT - Textclip device */
};

/****************************************************************************/

long
__pathconf(struct MsgPort *port,int name)
{
	ULONG dos_type = 0;
	size_t fs_index = 0;
	long ret = -1;

	if(port != NULL)
	{
		D_S(struct InfoData,id);

		if(DoPkt(port,ACTION_IS_FILESYSTEM,0,0,0,0,0) == DOSFALSE) /* Not a filesystem. */
		{
			SHOWMSG("Not a filesystem.");

			__set_errno(ENODEV);
			goto out;
		}

		if(DoPkt(port,ACTION_DISK_INFO,MKBADDR(id),0,0,0,0))	/* Managed to obtain disk info. */
		{
			size_t i;

			switch(id->id_DiskState)
			{
				case ID_VALIDATING:	/* Consider this an error condition? */
				case ID_WRITE_PROTECTED:
				case ID_VALIDATED:

					dos_type = id->id_DiskType;

					/* See if we know anything about this file-system */
					for(i = 0 ; i < NUM_ENTRIES(fs_info) ; i++)
					{
						if(dos_type == fs_info[i].dos_type)
						{
							fs_index = i;
							break;
						}
					}

					break;

				default:

					SHOWMSG("Invalid disk state.");
					break;
			}
		}
		else
		{
			/* Treat error as no disk present by having default fs_index=0 */
			SHOWMSG("Unable to query DISK_INFO");
		}
	}

	switch(name)
	{
		case _PC_FILESIZEBITS:

			ret = fs_info[fs_index].file_size_bits;
			break;

		case _PC_LINK_MAX:

			ret = fs_info[fs_index].link_max;
			break;

		case _PC_MAX_CANON:

			ret = 510;	/* I could not find any documentation regarding this. */
			break;

		case _PC_MAX_INPUT:

			#if defined(__amigaos4__)
			{
				uint32 Bufsize;
				struct TagItem TagList[2]=
				{
					{DC_FHBufferR,	(ULONG)&Bufsize},
					{TAG_DONE,		0}
				};

				DosControl(TagList);
				ret = Bufsize;	/* Default is 2048 bytes. */
			}
			#else
			{
				ret = 204;
			}
			#endif	/* __amigaos4__ */

			break;

		case _PC_NAME_MAX:

			ret = fs_info[fs_index].name_max;
			break;

		case _PC_PATH_MAX:

			ret = fs_info[fs_index].path_max;
			break;

		case _PC_PIPE_BUF:

			ret = 512;	/* One buffer. The PIPE: device usually has 8 of these. */
			break;

		case _PC_XATTR_ENABLED:

			ret = 0;
			break;

		case _PC_XATTR_EXISTS:

			ret = 0;
			break;

		case _PC_CHOWN_RESTRICTED:

			ret = 0;
			break;

		case _PC_NO_TRUNC:

			ret = 0;
			break;

		case _PC_VDISABLE:

			ret = 0;	/* TODO: Implement this in the termios emulation. */
			break;

		case _PC_ASYNC_IO:

			ret = 0;
			break;

		case _PC_PRIO_IO:

			ret = 0;
			break;

		case _PC_SYNC_IO:

			ret = 0;
			break;

		case _PC_SYMLINK_MAX:

			ret = fs_info[fs_index].symlink_max;
			break;

		case _PC_DOSTYPE:	/* Amiga-specific extension. */

			ret = dos_type;
			break;

		default:

			SHOWMSG("Invalid option name");
			__set_errno(EINVAL);
			goto out;
	}

 out:

	return(ret);
}
