Files
2015-04-16 09:16:48 +02:00

559 lines
13 KiB
C

/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Markus M. Wild
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* kern_descrip.c,v 1.1.1.1 1994/04/04 04:30:42 amiga Exp
*
* kern_descrip.c,v
* Revision 1.1.1.1 1994/04/04 04:30:42 amiga
* Initial CVS check in.
*
* Revision 1.2 1992/07/04 19:19:04 mwild
* add support for F_INTERNALIZE/F_EXTERNALIZE, which are used by IXPIPE
* and execve().
*
* Revision 1.1 1992/05/14 19:55:40 mwild
* Initial revision
*
*
* Since the code originated from Berkeley, the following copyright
* header applies as well. The code has been changed, it's not the
* original Berkeley code!
*/
/*
* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution is only permitted until one year after the first shipment
* of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
* binary forms are permitted provided that: (1) source distributions retain
* this entire copyright notice and comment, and (2) distributions including
* binaries display the following acknowledgement: This product includes
* software developed by the University of California, Berkeley and its
* contributors'' in the documentation or other materials provided with the
* distribution and in all advertising materials mentioning features or use
* of this software. Neither the name of the University nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)kern_descrip.c 7.16 (Berkeley) 6/28/90
*/
#define _KERNEL
#include "ixemul.h"
#include "kprintf.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <string.h>
/*
* Descriptor management.
*/
/*
* System calls on descriptors.
*/
/* ARGSUSED */
int
getdtablesize (void)
{
/* This was NOFILE, but getdtablesize is also used to determine the number
number of filehandles select() should test. And if you pass a value
larger than FD_SETSIZE to select(), you'll get fireworks. And it is very
hard to discover why your program won't work. I know: I've been through
this process twice now, so I thought I'd better fix this here by just
returning FD_SETSIZE.
I could also change the FD_SETSIZE macro to the value of NOFILE (changing
256 to 512), but that would be a waste of memory, and besides, in the
future the number of filehandles might become dynamic, so it wouldn't work
in any case. */
return FD_SETSIZE;
}
/*
* Duplicate a file descriptor.
*/
/* ARGSUSED */
int
dup (unsigned i)
{
struct file *fp;
int fd, error;
usetup;
//if (u.u_parent_userdata){u_ptr = u.u_parent_userdata;TRAP;}
if (i >= NOFILE || (fp = u.u_ofile[i]) == NULL)
errno_return(EBADF, -1);
if (fp->f_type == DTYPE_SOCKET)
{
struct file *fp2;
int fd2;
int err;
if ((err = falloc (&fp2, &fd2)))
errno_return(err, -1);
fp2->f_so = netcall(NET__dup, fp);
if (fp2->f_so == -1)
{
/* free the allocated fd */
u.u_ofile[fd2] = 0;
fp2->f_count = 0;
return -1;
}
fp2->f_socket_domain = fp->f_socket_domain;
fp2->f_socket_type = fp->f_socket_type;
fp2->f_socket_protocol = fp->f_socket_protocol;
_set_socket_params(fp2, fp->f_socket_domain, fp->f_socket_type, fp->f_socket_protocol);
return fd2;
}
if ((error = ufalloc (0, &fd)))
errno_return(error, -1);
u.u_ofile[fd] = fp;
u.u_pofile[fd] = u.u_pofile[i] &~ UF_EXCLOSE;
fp->f_count++;
if (fd > u.u_lastfile)
u.u_lastfile = fd;
return fd;
}
/*
* Duplicate a file descriptor to a particular value.
*/
/* ARGSUSED */
int
dup2 (unsigned i, unsigned j)
{
register struct file *fp;
int old_err;
usetup;
//if (u.u_parent_userdata){u_ptr = u.u_parent_userdata;TRAP;}
if (i >= NOFILE || (fp = u.u_ofile[i]) == NULL)
errno_return(EBADF, -1);
if (j < 0 || j >= NOFILE)
errno_return(EBADF, -1);
if (i == j) return (int)j;
ix_lock_base ();
old_err = errno;
if (u.u_ofile[j] && u.u_ofile[j]->f_close)
u.u_ofile[j]->f_close (u.u_ofile[j]);
u.u_ofile[j] = fp;
u.u_pofile[j] = u.u_pofile[i] &~ UF_EXCLOSE;
fp->f_count++;
if (j > u.u_lastfile)
u.u_lastfile = j;
ix_unlock_base ();
/*
* dup2() must suceed even though the close had an error.
*/
errno = old_err; /* XXX */
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return (int)j;
}
/*
* The file control system call.
*/
/* ARGSUSED */
int
fcntl(int fdes, int cmd, int arg)
{
register struct file *fp;
register char *pop;
int i, error;
usetup;
if (u.u_parent_userdata){u_ptr = u.u_parent_userdata;}
/* F_INTERNALIZE doesn't need a valid descriptor. Check for this first */
if (cmd == F_INTERNALIZE)
{
if ((error = ufalloc (0, &i)))
{
errno = error;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
fp = (struct file *) arg;
u.u_ofile[i] = fp;
u.u_pofile[i] = 0;
fp->f_count++;
return i;
}
if (fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
{
errno = EBADF;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
pop = &u.u_pofile[fdes];
switch (cmd)
{
case F_DUPFD:
if (arg < 0 || arg >= NOFILE)
{
errno = EINVAL;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
if ((error = ufalloc (arg, &i)))
{
errno = error;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
ix_lock_base ();
u.u_ofile[i] = fp;
u.u_pofile[i] = *pop &~ UF_EXCLOSE;
fp->f_count++;
ix_unlock_base ();
if (i > u.u_lastfile) u.u_lastfile = i;
return i;
case F_GETFD:
return *pop & 1;
case F_SETFD:
*pop = (*pop &~ 1) | (arg & 1);
return 0;
case F_GETFL:
return OFLAGS(fp->f_flags);
case F_SETFL:
fp->f_flags &= ~FCNTLFLAGS;
fp->f_flags |= FFLAGS(arg) & FCNTLFLAGS;
if (fp->f_type == DTYPE_SOCKET)
{
arg = (fp->f_flags & FASYNC) ? 1 : 0;
ioctl(fdes, FIOASYNC, &arg);
arg = (fp->f_flags & FNONBLOCK) ? 1 : 0;
ioctl(fdes, FIONBIO, &arg);
}
return 0;
case F_EXTERNALIZE:
return (int)fp;
default:
errno = EINVAL;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
/* NOTREACHED */
}
/*
* Return status information about a file descriptor.
*/
/* ARGSUSED */
int
fstat (int fdes, struct stat *sb)
{
struct file *fp;
usetup;
if (u.u_parent_userdata)fp = u.u_parent_userdata->u_ofile[fdes];
else fp = u.u_ofile[fdes];
if (fdes >= NOFILE || (fp == NULL))
{
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
errno = EBADF;
return -1;
}
/* I found this code from the AmiTCP sdk. It *should* work with AS225 */
if (fp->f_type == DTYPE_SOCKET && u.u_ixnetbase)
return netcall(NET__fstat, fp, sb);
/* if this file is writable, then it's quite probably that the stat buffer
information stored at open time is no longer valid. So if the file really
is a file, update that information */
if ((fp->f_flags & FWRITE) && fp->f_type == DTYPE_FILE)
__fstat (fp);
*sb = fp->f_stb;
return 0;
}
/*
* Allocate a user file descriptor.
*/
int
ufalloc(int want, int *result)
{
usetup;
if (u.u_parent_userdata)u_ptr = u.u_parent_userdata;
for (; want < NOFILE; want++)
{
if (u.u_ofile[want] == NULL)
{
u.u_pofile[want] = 0;
if (want > u.u_lastfile) u.u_lastfile = want;
*result = want;
return 0;
}
}
return EMFILE;
}
/*
* Allocate a user file descriptor
* and a file structure.
* Initialize the descriptor
* to point at the file structure.
*/
int
falloc(struct file **resultfp, int *resultfd)
{
register struct file *fp;
int error, i;
usetup;
if (u.u_parent_userdata)u_ptr = u.u_parent_userdata;
if ((error = ufalloc(0, &i)))
return (error);
ix_lock_base ();
#if USE_DYNFILETAB
{
struct MinNode *node;
node = REMHEAD(&ix.ix_free_file_list);
if (node)
{
fp = (void *) (node + 1);
ADDHEAD(&ix.ix_used_file_list, node);
goto slot;
}
node = kmalloc(sizeof(struct MinNode) + sizeof(struct file));
if (node)
{
fp = (void *) (node + 1);
memset(fp, 0, sizeof(struct file));
ADDHEAD(&ix.ix_used_file_list, node);
goto slot;
}
//ix_warning("ixemul.library out of memory!");
error = ENOMEM;
}
#else
if (ix.ix_lastf == 0)
ix.ix_lastf = ix.ix_file_tab;
for (fp = ix.ix_lastf; fp < ix.ix_fileNFILE; fp++)
if (fp->f_count == 0)
goto slot;
for (fp = ix.ix_file_tab; fp < ix.ix_lastf; fp++)
if (fp->f_count == 0)
goto slot;
/* YES I know.. it's not optimal, we should resize the table...
* unfortunately all code accessing file structures will then have
* to be changed as well, and this is a job for later improvement,
* first goal is to get this baby working... */
ix_warning("ixemul.library file table full!");
error = ENFILE;
#endif
goto do_ret;
slot:
u.u_ofile[i] = fp;
fp->f_stb_dirty = 0;
fp->f_name = 0;
fp->f_count = 1;
fp->f_type = 0; /* inexistant type ;-) */
memset(&fp->f__fh, 0, sizeof(fp->f__fh));
#if !USE_DYNFILETAB
ix.ix_lastf = fp + 1;
#endif
if (resultfp)
*resultfp = fp;
if (resultfd)
*resultfd = i;
error = 0;
do_ret:
ix_unlock_base();
return error;
}
int
ufalloc2(int want, int *result)
{
usetup;
//if (u.u_parent_userdata)u_ptr = u.u_parent_userdata;
for (; want < NOFILE; want++)
{
if (u.u_ofile[want] == NULL)
{
u.u_pofile[want] = 0;
if (want > u.u_lastfile) u.u_lastfile = want;
*result = want;
return 0;
}
}
return EMFILE;
}
/*
* Allocate a user file descriptor
* and a file structure.
* Initialize the descriptor
* to point at the file structure.
*/
int
falloc2(struct file **resultfp, int *resultfd)
{
register struct file *fp;
int error, i;
usetup;
//if (u.u_parent_userdata)u_ptr = u.u_parent_userdata;
if ((error = ufalloc(0, &i)))
return (error);
ix_lock_base ();
#if USE_DYNFILETAB
{
struct MinNode *node;
node = REMHEAD(&ix.ix_free_file_list);
if (node)
{
fp = (void *) (node + 1);
ADDHEAD(&ix.ix_used_file_list, node);
goto slot;
}
node = kmalloc(sizeof(struct MinNode) + sizeof(struct file));
if (node)
{
fp = (void *) (node + 1);
memset(fp, 0, sizeof(struct file));
ADDHEAD(&ix.ix_used_file_list, node);
goto slot;
}
//ix_warning("ixemul.library out of memory!");
error = ENOMEM;
}
#else
if (ix.ix_lastf == 0)
ix.ix_lastf = ix.ix_file_tab;
for (fp = ix.ix_lastf; fp < ix.ix_fileNFILE; fp++)
if (fp->f_count == 0)
goto slot;
for (fp = ix.ix_file_tab; fp < ix.ix_lastf; fp++)
if (fp->f_count == 0)
goto slot;
/* YES I know.. it's not optimal, we should resize the table...
* unfortunately all code accessing file structures will then have
* to be changed as well, and this is a job for later improvement,
* first goal is to get this baby working... */
ix_warning("ixemul.library file table full!");
error = ENFILE;
#endif
goto do_ret;
slot:
u.u_ofile[i] = fp;
fp->f_stb_dirty = 0;
fp->f_name = 0;
fp->f_count = 1;
fp->f_type = 0; /* inexistant type ;-) */
memset(&fp->f__fh, 0, sizeof(fp->f__fh));
#if !USE_DYNFILETAB
ix.ix_lastf = fp + 1;
#endif
if (resultfp)
*resultfp = fp;
if (resultfd)
*resultfd = i;
error = 0;
do_ret:
ix_unlock_base();
return error;
}
void ffree(struct file *f)
{
#if USE_DYNFILETAB
if (f)
{
struct MinNode *node = ((struct MinNode *) f) - 1;
/* Remove from ix_used_file_list */
REMOVE(node);
ADDHEAD(&ix.ix_free_file_list, node);
}
#endif
}
/*
* Apply an advisory lock on a file descriptor.
*/
/* ARGSUSED */
int
flock (int fdes, int how)
{
return 0; /* always succeed */
}