From: "Mark E." To: djgpp-workers AT delorie DOT com Date: Mon, 23 Oct 2000 14:43:24 -0400 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT 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: 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 #include #include #include #include #include #include #include #include #include #include #include #include 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; }