Mail Archives: djgpp-workers/2000/10/23/14:43:27
> So I'd suggest to write flock that uses 21/51, and add some ifdef'ed code
> to Perl that if flock fails on DOS, to ignore the failure. (If you don't
> know how to tell whether you run on Windows, check out Int 2Fh/AX=1600h.)
I still have an enhanced version of fcntl that needs to be finished that can
probably help once finished:
/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#include <libc/stubs.h>
#include <dpmi.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <io.h>
#include <sys/fsext.h>
#include <sys/movedata.h>
#include <sys/farptr.h>
#include <libc/dosio.h>
#include <libc/getdinfo.h>
#include <go32.h>
static unsigned long _get_sft_entry_ptr(int fd)
{
__dpmi_regs regs;
unsigned char index;
unsigned long es, di;
/* Get the JFT entry address for this handle. */
regs.x.ax = 0x1220;
regs.x.bx = fd;
__dpmi_int(0x2f, ®s);
if (regs.x.flags & 1)
{
errno = ENOSYS;
return 0;
}
/* Get the SFT entry number for this handle. */
es = regs.x.es;
di = regs.x.di;
index = _farpeekb(_dos_ds, es * 16 + di);
/* Now get the address of the entry. */
regs.x.ax = 0x1216;
regs.x.bx = index;
__dpmi_int (0x2f, ®s);
if (regs.x.flags & 1)
{
errno = ENOSYS;
return 0;
}
es = regs.x.es;
di = regs.x.di;
return es * 16 + di;
}
static int
inherit_bit_test (int fd, short dev_info)
{
__dpmi_regs regs;
short new_dev_info;
dev_info |= _DEV_NO_INHERIT;
regs.x.ax = 0x4401;
regs.x.bx = fd;
regs.x.dx = dev_info;
__dpmi_int(0x21, ®s);
new_dev_info = _get_dev_info(fd);
/* If the dev info words are equal, then the documented
interface can't be used to set the inheritance bit. */
return (new_dev_info == dev_info) ? 1 : 0;
}
int
fcntl(int fd, int cmd, ...)
{
int tofd, open_max;
va_list ap;
__FSEXT_Function *func;
short dev_info = _get_dev_info(fd);
static int inherit_bit_visible = -1;
int errno_save;
/* Verify the descriptor is valid by retrieving
the handle's device info word. */
if (dev_info == -1)
return dev_info;
/* Allow a fd to override with a FSEXT. */
func = __FSEXT_get_function(fd);
if (func)
{
int rv;
if (func(__FSEXT_fcntl, &rv, &fd))
return rv;
}
errno_save = errno;
switch (cmd)
{
case F_DUPFD:
{
va_start(ap, cmd);
tofd = va_arg(ap, int);
va_end(ap);
open_max = getdtablesize();
while (tofd < open_max)
{
/* If unable to get the device info for the handle,
then the handle is not active and it can be used. */
if (_get_dev_info(tofd) == -1)
break;
tofd++;
}
if (tofd >= open_max)
{
errno = EMFILE;
return -1;
}
errno = errno_save;
return dup2(fd, tofd);
}
case F_GETFD:
{
unsigned long entry_ptr;
/* DOS only passes the first 20 handles to child programs. In
addition, handles 19 and 18 will be closed by the stub of the
child program (if it is a DJGPP program). */
if (fd >= 18)
return FD_CLOEXEC;
/* Determine if the documented interface will allow twiddling with
the inherit bit. If not, fallback to the undocumented one. */
if (inherit_bit_visible == -1)
inherit_bit_visible = inherit_bit_test (fd, dev_info);
if (!inherit_bit_visible)
{
entry_ptr = _get_sft_entry_ptr(fd);
if (entry_ptr == 0)
{
/* The fd has already been validated, so reaching here means
something is wrong with _get_sft_entry_ptr. */
return -1;
}
/* Offset 5 in the SFT contains the device info word. */
dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
}
return (dev_info & _DEV_NO_INHERIT) ? FD_CLOEXEC : 0;
}
case F_SETFD:
{
unsigned int flag;
unsigned long entry_ptr = 0; /* shut up -Wall */
__dpmi_regs regs;
va_start (ap, cmd);
flag = va_arg(ap, int);
va_end(ap);
/* DOS only passes the first 20 handles to child programs. In
addition, handles 19 and 18 will be closed by the stub of the
child program (if it is a DJGPP program). */
if (fd >= 18)
{
if (flag & FD_CLOEXEC)
return 0;
else
{
errno = ENOSYS;
return -1;
}
}
/* Determine if the documented interface will allow twiddling with
the inherit bit. If not, fallback to the undocumented one. */
if (inherit_bit_visible == -1)
inherit_bit_visible = inherit_bit_test(fd, dev_info);
if (!inherit_bit_visible)
{
entry_ptr = _get_sft_entry_ptr(fd);
if (entry_ptr == 0)
{
/* The fd has already been validated, so reaching here means
something is wrong with _get_sft_entry_ptr. */
return -1;
}
dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
}
if (flag & FD_CLOEXEC)
dev_info |= _DEV_NO_INHERIT;
else
dev_info &= ~(_DEV_NO_INHERIT);
if (inherit_bit_visible)
{
regs.x.ax = 0x4401;
regs.x.bx = fd;
regs.x.dx = dev_info;
__dpmi_int(0x21, ®s);
}
else
_farpokew(_dos_ds, entry_ptr + 5, dev_info);
return 0;
}
case F_GETFL:
{
return 0;
}
case F_SETFL:
{
unsigned char new_mode_bits;
va_start (ap, cmd);
new_mode_bits = va_arg(ap,int);
va_end(ap);
/* Allow removal of O_NONBLOCK, since DJGPP doesn't support it
anyway. */
return (new_mode_bits == 0) ? 0 : -1;
}
case F_GETLK:
case F_SETLK:
case F_SETLKW:
{
struct flock *lock_req = NULL; /* shut up -Wall */
int ret = -1;
off_t pos, cur_pos, lock_pos;
off_t len;
cur_pos = lseek(fd, 0, SEEK_CUR);
va_start (ap, cmd);
lock_req = va_arg(lock_req, struct flock *);
va_end (ap);
lock_pos = lseek (fd, lock_req->l_start, lock_req->l_whence);
len = lock_req->l_len;
/* If l_len is zero, then the lock is to be set from l_start
until the end-of-file. */
if (len == 0)
{
len = filelength(fd) - cur_pos;
/* This should probably be an error. */
if (len <= 0)
len = 1;
}
lseek (fd, cur_pos, SEEK_SET);
/* If l_len is positive, the area to lock is from l_start
to l_start + l_len - 1. If l_len is negative, the area to lock is
from l_start + len to l_start - 1. */
if (len > 0)
{
pos = lock_pos;
}
else
{
pos = lock_pos + len;
len = -lock_req->l_len;
}
/* DOS/Windows only support read locks on a per-file basis,
so any attempted use of a read lock is an error. */
if (lock_req->l_type == F_RDLCK)
{
errno = ENOSYS;
return -1;
}
if (lock_req->l_type == F_UNLCK)
{
ret = _dos_unlock(fd, pos, len);
}
else if (lock_req->l_type == F_WRLCK)
{
ret = _dos_lock(fd, pos, len);
if (cmd == F_GETLK)
if (ret == 0)
{
_dos_unlock(fd, pos, len);
/* If no lock is found that would prevent a lock from
being created, the lock type is set to F_UNLCK. */
lock_req->l_type = F_UNLCK;
}
else
{
/* If a lock is found then l_whence, l_start, and l_len
should point to the area covered by the lock. But the
file locking interface doesn't report where the
existing lock is, so nothing more can be done. */
;
}
/* If F_SETLKW is set, wait for the lock to be released. */
if (cmd == F_SETLKW && ret < 0)
while ((ret = _dos_lock(fd, pos, len)) < 0)
__dpmi_yield();
}
if (ret < 0)
errno = ENOSYS;
return ret;
}
}
/* In case fcntl is called with an unrecognized command. */
errno = ENOSYS;
return -1;
}
- Raw text -