Mail Archives: djgpp-workers/2000/11/19/02:39:06
--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"; format=flowed
OK, I have gotten Mark's locking version of fcntl into what looks to me
like working order. I have attached a diff to the current v2.03 fcntl,
a complete version and a small test program.
Please test it on your systems. The test program just prints the
return code from various calls to fcntl, it's not a very complete test
yet but it is a small beginning. I will try to make up a more complete
test program and post it later. As Mark did, I mainly used it to step
through the code with gdb to find problems.
I have built libc with this version and then built a recent bleedperl
release (perl AT 7707) with the new libc. Perl seems to like it; perl
uses the locking functions of fcntl to simulate flock and passes both
basic perl flock tests and tests using the emulated flock in the
Storable module tests. There was one locking-related patch needed to
Storable.pm, and I have submitted that to the p5p list.
The F_GETLK function is not yet working properly, but I hope to have
that fixed soon.
For those interested, the main change I made to Mark's version was the
assignment to lock_req in the F_SETLK... section. Mark had coded this:
va_start (ap, cmd);
lock_req = va_arg(lock_req, struct flock *);
va_end (ap);
What was needed was this:
va_start (ap, cmd);
lock_req = va_arg(ap, struct flock *);
va_end (ap);
Notice the difference in the argument to va_arg.
I also allowed F_RDLCK requests to proceed under the following
conditions:
lock_req->l_whence = SEEK_SET
lock_req->l_start == 0
lock_req->l_len == 0
Under these conditions, F_RDLCK is equivalent to a file-level lock, so
I saw no harm in allowing it.
Comments, errata, etc. welcome.
Enjoy.
--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="fcntl.dif"
--- libc/posix/fcntl/fcntl.c0 Thu Jun 3 13:27:38 1999
+++ libc/posix/fcntl/fcntl.c Fri Nov 17 20:08:00 2000
@@ -1,3 +1,4 @@
+/* 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 */
@@ -7,28 +8,101 @@
#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>
-static int
-is_used_fd(int fd)
+
+#include <go32.h>
+
+
+static unsigned long _get_sft_entry_ptr(int fd)
{
__dpmi_regs regs;
+ unsigned char index;
+ unsigned long es, di;
- regs.x.ax = 0x4400;
+
+ /* Get the JFT entry address for this handle. */
+ regs.x.ax = 0x1220;
regs.x.bx = fd;
- __dpmi_int(0x21, ®s);
+ __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;
- return 1;
+
+ 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 = __FSEXT_get_function(fd);
+ __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;
@@ -36,62 +110,272 @@
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();
- if (tofd < 0 || tofd >= open_max)
+ case F_DUPFD:
{
- errno = EINVAL;
- return -1;
+ 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);
}
- while (tofd < open_max)
+
+
+ case F_GETFD:
{
- if (! is_used_fd(tofd))
- break;
- tofd++;
+ 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;
}
- if (tofd >= open_max)
+
+ case F_SETFD:
{
- errno = EMFILE;
- return -1;
+ 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;
}
- return dup2(fd, tofd);
-
- case F_GETFD:
- /* 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).
- FIXME: we should look at the no-inherit bit stashed in the SFT
- entry pointed to by the handle, since some of the first 18
- handles could have been opened with a no-inherit bit. */
- return fd >= 18 ? FD_CLOEXEC : 0;
- case F_SETFD:
- if ((fd < 18) ^ ((cmd & FD_CLOEXEC) != 0))
+ case F_GETFL:
+ {
return 0;
- else
+ }
+
+
+ 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(ap, 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)
{
- errno = ENOSYS;
- return -1;
+ len = filelength(fd) - cur_pos;
+ /* This should probably be an error. */
+ if (len <= 0)
+ len = 1;
}
- case F_GETFL:
- return 0; /* FIXME: should use the data in the SFT */
- case F_SETFL:
- errno = ENOSYS;
- return -1;
- case F_GETLK:
- case F_SETLK:
- case F_SETLKW:
- errno = ENOSYS;
- return -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,
+ UNLESS all of these conditions are true, which makes the
+ request into a per-file lock equivalent to F_WRLCK:
+
+ lock_req->l_whence = SEEK_SET
+ lock_req->l_start == 0
+ lock_req->l_len == 0
+ */
+ if ((lock_req->l_type == F_RDLCK) &&
+ (lock_req->l_whence != SEEK_SET ||
+ lock_req->l_start != 0 ||
+ lock_req->l_len != 0))
+ {
+ 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) || (lock_req->l_type == F_RDLCK))
+ {
+ 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;
}
--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="fcntl.c"
/* 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(ap, 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,
UNLESS all of these conditions are true, which makes the
request into a per-file lock equivalent to F_WRLCK:
lock_req->l_whence = SEEK_SET
lock_req->l_start == 0
lock_req->l_len == 0
*/
if ((lock_req->l_type == F_RDLCK) &&
(lock_req->l_whence != SEEK_SET ||
lock_req->l_start != 0 ||
lock_req->l_len != 0))
{
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) || (lock_req->l_type == F_RDLCK))
{
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;
}
--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="tfcntl.c"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
#if defined(F_SETLK) && defined(F_SETLKW)
struct flock flock;
int retval, fd;
fd = open("tfcntl.c", O_RDONLY);
flock.l_type = F_RDLCK;
flock.l_whence = SEEK_SET;
flock.l_start = flock.l_len = 0;
retval = fcntl(fd, F_SETLK, &flock);
printf("F_SETLK/F_RDLCK:retval=%d\n", retval);
if (retval < 0) exit(2);
retval = fcntl(fd, F_GETLK, &flock);
printf("F_GETLK:retval=%d\n", retval);
flock.l_type = F_UNLCK;
retval = fcntl(fd, F_SETLK, &flock);
printf("F_SETLK/F_UNLCK:retval=%d\n", retval);
if (retval < 0) exit(3);
retval = fcntl(fd, F_GETFD);
printf("F_GETFD:retval=%04x\n", retval);
retval = fcntl(fd, F_SETFL, O_BINARY);
printf("F_SETFL:retval=%04x\n", retval);
retval = fcntl(fd, F_GETFL);
printf("F_GETFL:retval=%04x\n", retval);
close(fd);
if (retval < 0) exit(4);
exit(0);
#else
exit(99);
#endif
}
--=====================_55779254==_
Content-Type: text/plain; charset="us-ascii"; format=flowed
---------------------------------------------------------
Peter J. Farley III (pjfarley AT dorsai DOT org OR
pjfarley AT banet DOT net)
--=====================_55779254==_--
- Raw text -