delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/05/27/21:32:08

Message-Id: <199905280131.BAA105100@out2.ibm.net>
From: "Mark E." <snowball3 AT bigfoot DOT com>
To: djgpp-workers AT delorie DOT com
Date: Thu, 27 May 1999 21:32:22 -0400
MIME-Version: 1.0
Subject: enhancements to fcntl.c
X-mailer: Pegasus Mail for Win32 (v3.11)
Reply-To: djgpp-workers AT delorie DOT com

Hello,

Bash uses fcntl with F_GETFD to check if a file descriptor is valid. To 
support this in a future port, I enhanced fcntl to check if the descriptor is 
valid. While I was at it, I made a go a implementing the rest of the 
commands using the online Unix spec as my reference.

Corrections, suggestions, and criticisms are welcome.

/* 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 <sys/fsext.h>
#include <sys/movedata.h>

static int
is_used_fd(int fd)
{
  __dpmi_regs regs;

  regs.x.ax = 0x4400;
  regs.x.bx = fd;
  __dpmi_int(0x21, &regs);
  if (regs.x.flags & 1)
    return 0;

  return 1;
}

static int get_sft_entry(int fd, char sft_entry[])
{
  __dpmi_regs regs;
  unsigned char index;

  /* Get JFT entry address.  */
  regs.x.ax = 0x1220;
  regs.x.bx = fd;
  __dpmi_int (0x2f, &regs);

  if (regs.x.flags & 1)
    return -1;

  /* First byte is the SFT entry number.  */
  dosmemget(regs.x.es * 16 + regs.x.di, 1, &index);

  /* Get the SFT entry for the handle.  */
  regs.x.ax = 0x1216;
  regs.x.bx = index;
  __dpmi_int (0x2f, &regs);

  if (regs.x.flags & 1)
    return -1;

  dosmemget(regs.x.es * 16 + regs.x.di, 63, sft_entry);
  return 0;
}

static void
make_lock_args (int fd, struct flock *lck, off_t *_start, off_t *_len)
{
  off_t cur_pos = lseek (fd, 0, SEEK_CUR);
  off_t lock_pos = lseek (fd, lck->l_start, lck->l_whence);
  off_t len =  lck->l_len;

  /* If l_len is zero, then lock is to be set from l_start
     until the end-of-file. */
  if (len == 0)
  {
    len = filelength(fd) - cur_pos;
    if (len <= 0)
      len = 1;
  }

  lseek (fd, cur_pos, SEEK_SET);

  /* If l_len is positive, the area to lock is to be set 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 (lck->l_len > 0)
  {
    *_start = lock_pos;
    *_len = lck->l_len;
  }
  else
  {
    *_start = lock_pos + lck->l_len;
    *_len = -lck->l_len;
  }
}

int
fcntl(int fd, int cmd, ...)
{
  int tofd, open_max;
  va_list ap;
  __FSEXT_Function *func = __FSEXT_get_function(fd);

  /* Before proceeding, verify the descriptor is valid.  */
  if (!is_used_fd(fd))
  {
    errno = EINVAL;
    return -1;
  }

  if (func)
  {
    int rv;
    if (func(__FSEXT_fcntl, &rv, &fd))
      return rv;
  }

  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 (! is_used_fd(tofd))
          break;
        tofd++;
      }

      if (tofd >= open_max)
      {
        errno = EMFILE;
        return -1;
      }

      return dup2(fd, tofd);
    }

    case F_SETFD:
    {
      int flag;

      /* Return error if any descriptor flags are passed, since
         DOS doesn't support them.  */
      va_start (ap, cmd);
      flag = va_arg(ap, int);
      va_end(ap);
      return (flag ? -1 : 0);
    }

    case F_GETFD:
      /* DOS does not support FD_CLOEXEC or any other descriptor 
flags,
         so there are no flags to return.  */
      return 0;

    case F_GETFL:
    {
      char sft_entry[64];
      if (get_sft_entry(fd, sft_entry) < 0)
        return -1;

      /* Return the file access mode associated with the descriptor.  */
      return sft_entry[2];
    }

    case F_SETFL:
      return 0;

    case F_GETLK:
    case F_SETLK:
    case F_SETLKW:
    {
      struct flock *lock_req = va_arg(lock_req, struct flock *);
      int ret = -1;
      off_t pos, len;
      make_lock_args(fd, lock_req, &pos, &len);

      /* Ignore read locks because DOS/Windows support only write locks
         for record locking.  */
      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 (ret == 0 && cmd == F_GETLK)
          _dos_unlock(fd, pos, len);
      }
      return ret;
    }
  }
  return -1;
}

--- 
Mark Elbrecht, snowball3 AT bigfoot DOT com
http://snowball.frogspace.net/

- Raw text -


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