Mail Archives: djgpp-workers/2001/08/21/09:15:56
> > From: "Andrew Cottrell" <acottrel AT ihug DOT com DOT au>
> > Date: Mon, 20 Aug 2001 23:58:40 +1000
> >
> > > If _is_executable is the suspect, it can be disabled by setting the
> > > _STAT_EXEC_MAGIC bit in _djstat_flags.
> > In my testing I found that I can "fix" the problem by one of the
following
> > methods:
> > a) Commenting out the _is_executable() call in fstat.c
> > b) Setting the _STAT_EXEC_MAGIC bit in _djstat_flags
> > b) adding a _read() to the _is_executable() function before or
after
> > the second 4200 call.
> > c) Debug the new sample under Rhide
>
> I don't understand the (c) above (it's probably due to the fact that
> RHIDE and GDB use FSEXT to watch handle usage by the debuggee), but
> otherwise it sounds like _is_executable is the prime suspect. But I
> cannot figure out why: all it does is move the file pointer (which is
> actually a no-op, since stdin was not read yet), reads two bytes, and
> then moves the file pointer again. One idea would be to selectively
> disable parts of _is_executable and see which one(s) cause the
> problem.
I found that the problem appears to be in the 3F00 call. I have included a
sample app below that can be used to debug and test any changes.
If I comment out the 3F00 call and instead use _read() these also cause the
problem to occur, this is expected as _read() also calls 3F00.
The output from the sample app I am using (with allow more conditional
printf's and #if 0... for debugging) is:
seek.c 178 4200, flags = 0x02 pos = 0x0000:0000 Char at offset [0] = (3)
seek.c 178 4200, flags = 0x02 pos = 0x0000:0001 Char at offset [1] = (4)
seek.c 178 4200, flags = 0x02 pos = 0x0000:0000 Char at offset [0] = (1)
seek.c 178 4200, flags = 0x02 pos = 0x0000:0001 Char at offset [1] = (2)
seek.c 178 4200, flags = 0x02 pos = 0x0000:0002 Char at offset [2] = (3)
Taking a wild guess could this be something to do with the STDIN being
openned as a LFN and the 3F00 requiring a SFN type handle? (I have no idea
how the STDIN handle is setup.)
> > I tried to find where STDIN is setup, but I couldn't see it. I do not
think
> > I am looking for the right thing. I searched for STDIN and couldn't see
> > anything useful, I loked in crt1.c. Could someone please point me in the
> > direction of where STDIN is setup/configured?
>
> What ``setup'' exactly are you looking for?
>
> stdin is a buffered stream, and its set up in
> src/libc/ansi/stdio/stdin.c. But I don't think this is relevant to
> the issue at hand, since we now know the problem is with lseek, not
> with fseek. And lseek works on the file handle, not on the FILE
> object. File handle zero is the one which corresponds to standard
> input, and the shell connects that handle to the file when you
> redirect it.
>
> Does that answer your question?
Yes it does for the setup of the file object.
#include <libc/stubs.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <dpmi.h>
#include <go32.h>
#include <io.h>
#include <libc/farptrgs.h>
#include <libc/dosio.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/stat.h>
#define STDIN_FILENO 0
/* TEST FILE IS 123456789ABCDEF */
unsigned short ac_get_magic(const char *s, int fh);
off_t aclseek(int handle, off_t offset, int whence);
unsigned short ac_get_magic(const char *s, int fh)
{
__dpmi_regs regs;
unsigned short retval;
unsigned short fpos_high = 0, fpos_low = 0;
int read_fail = 0;
int c1,c2;
printf("%s %d\n",__FILE__, __LINE__);
regs.x.ax = 0x4201; /* set pointer from current position */
regs.x.bx = fh;
regs.x.cx = regs.x.dx = 0; /* move 0 bytes (i.e., stay put) */
__dpmi_int(0x21, ®s);
if (regs.x.flags & 1)
{
printf("%s %d FAIL\n",__FILE__, __LINE__);
return 0;
}
printf("%s %d 4200, pos = 0x%04X:%04X\n",__FILE__, __LINE__,
regs.x.dx,regs.x.ax);
fpos_high = regs.x.dx; /* got current position */
fpos_low = regs.x.ax;
printf("%s %d 4200, fh = %d, read pos = 0x%04X:%04X\n",__FILE__,
__LINE__, fh, fpos_high, fpos_low);
regs.x.ax = 0x4200; /* set pointer from the beginning of file */
regs.x.cx = regs.x.dx = 0; /* move to beginning of file */
__dpmi_int(0x21, ®s);
if (regs.x.flags & 1)
{
printf("%s %d FAIL\n",__FILE__, __LINE__);
return 0;
}
printf("%s %d 4200, goto zero pos = 0x%04X:%04X\n",__FILE__, __LINE__,
regs.x.dx,regs.x.ax);
#if 1
// _read(fh,&c1,1);
// _read(fh,&c2,1);
//#else
/*
INT 21 - DOS 2+ - "READ" - READ FROM FILE OR DEVICE
AH = 3Fh
BX = file handle
CX = number of bytes to read
DS:DX -> buffer for data
Return: CF clear if successful
AX = number of bytes actually read (0 if at EOF before call)
CF set on error
AX = error code (05h,06h) (see #01680 at AH=59h/BX=0000h)
Notes: data is read beginning at current file position, and the file
position
is updated after a successful read
the returned AX may be smaller than the request in CX if a partial
read occurred
if reading from CON, read stops at first CR
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
BUG: Novell NETX.EXE v3.26 and 3.31 do not set CF if the read fails
due to
a record lock (see AH=5Ch), though it does return AX=0005h; this
has been documented by Novell
SeeAlso: AH=27h,AH=40h,AH=93h,INT 2F/AX=1108h,INT 2F/AX=1229h
*/
/* Read 2 bytes from the file. */
regs.x.ax = 0x3f00;
regs.x.bx = fh;
regs.x.cx = 2;
regs.x.ds = __tb_segment;
regs.x.dx = __tb_offset;
__dpmi_int(0x21, ®s);
/* We can either (1) succeed, (2) read less than 2 bytes,
or (3) fail to read at all. */
if ((regs.x.ax != 2) || (regs.x.flags & 1))
{
printf("%s %d FAIL\n",__FILE__, __LINE__);
read_fail = (regs.x.flags & 1) ? regs.x.ax : -1;
}
printf("%s %d 0x3F00 call result flags regs.x.ax = 0x%04x\n",__FILE__,
__LINE__,regs.x.ax);
#endif
regs.x.ax = 0x4200; /* set pointer from the beginning of file */
regs.x.bx = fh;
regs.x.cx = regs.x.dx = 0; /* move to beginning of file */
__dpmi_int(0x21, ®s);
if (regs.x.flags & 1)
{
printf("%s %d FAIL\n",__FILE__, __LINE__);
return 0;
}
printf("%s %d 4200 goto zero results, flags = %d, fh = %d, fpos_high=
%d, fpos_low = %d\n",__FILE__, __LINE__, regs.x.flags, fh, regs.x.dx,
regs.x.ax);
regs.x.ax = 0x4200; /* set pointer from the beginning of file */
regs.x.bx = fh;
regs.x.cx = fpos_high;
regs.x.dx = fpos_low;
__dpmi_int(0x21, ®s);
if (regs.x.flags & 1)
{
printf("%s %d Failure code = %d\n",__FILE__, __LINE__,regs.x.ax);
return 0;
}
printf("%s %d 4200 results, flags = %d, fh = %d, fpos_high= %d, fpos_low
= %d\n",__FILE__, __LINE__, regs.x.flags, fh, regs.x.dx, regs.x.ax);
if (read_fail == 0)
{
printf("%s %d return \n",__FILE__, __LINE__,c1,c2);
#if 1
retval = (c1 << 8 ) + c2;
#else
retval = _farpeekw(_dos_ds, __tb);
#endif
}
else
{
/* The file couldn't be read: assume non-executable. If the file
*is* executable, but was passed as a file-handle, and the user
opened it in write-only mode, they lose... */
printf("%s %d\n",__FILE__, __LINE__);
retval = 0;
if (read_fail != -1)
{
printf("%s %d FAIL\n",__FILE__, __LINE__);
errno = __doserr_to_errno(read_fail);
}
}
printf("%s %d\n",__FILE__, __LINE__);
return retval;
}
off_t aclseek(int handle, off_t offset, int whence)
{
__dpmi_regs r;
r.h.ah = 0x42;
r.h.al = whence;
r.x.bx = handle;
r.x.cx = offset >> 16;
r.x.dx = offset & 0xffff;
__dpmi_int(0x21, &r);
if (r.x.flags & 1)
{
printf("%s %d FAIL\n",__FILE__, __LINE__);
return -1;
}
printf("%s %d 42%02d, flags = 0x%02X pos = 0x%04X:%04X ",__FILE__,
__LINE__, whence, r.x.flags, r.x.dx,r.x.ax);
return (r.x.dx << 16) + r.x.ax;
}
int seekerprint(int offset)
{
int c, seeker;
seeker = aclseek(STDIN_FILENO,offset,SEEK_SET);
_read(STDIN_FILENO,&c,1);
printf("Char at offset [%d] = (%c)\n", offset, c);
return seeker;
}
int main (void)
{
int c, magic_number, seeker;
magic_number = ac_get_magic((const char *)0, STDIN_FILENO);
printf("magic_number = 0x%04X\n",magic_number);
seeker = seekerprint(0); /* fail */
seeker = seekerprint(1); /* Fail */
seeker = seekerprint(0); /* Pass */
seeker = seekerprint(1); /* Pass */
seeker = seekerprint(2); /* Pass */
return(0);
}
- Raw text -