delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/10/23/14:43:27

From: "Mark E." <snowball3 AT bigfoot DOT com>
To: djgpp-workers AT delorie DOT com
Date: Mon, 23 Oct 2000 14:43:24 -0400
MIME-Version: 1.0
Subject: Re: New versions of perl require "flock" or working "fcntl(fh, F_SETLK/W,...)"
Message-ID: <39F44E8C.20662.102214@localhost>
References: <4 DOT 3 DOT 1 DOT 0 DOT 20001023101622 DOT 00af2d10 AT pop5 DOT banet DOT net>
In-reply-to: <Pine.SUN.3.91.1001023172313.15701G-100000@is>
X-mailer: Pegasus Mail for Win32 (v3.12c)
Reply-To: djgpp-workers AT delorie DOT com

> 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, &regs);

  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, &regs);
  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, &regs);
  
  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, &regs);
      }
      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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019