delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2001/08/22/08:53:40

X-Authentication-Warning: smtp3.ihug.com.au: Host p19-max39.syd.ihug.com.au [203.173.148.83] claimed to be acceleron
Message-ID: <00ae01c12b02$75f9d200$0a02a8c0@acceleron>
From: "Andrew Cottrell" <acottrel AT ihug DOT com DOT au>
To: "Eli Zaretskii" <eliz AT is DOT elta DOT co DOT il>
Cc: <sandmann AT clio DOT rice DOT edu>, <djgpp-workers AT delorie DOT com>
References: <10108200508 DOT AA15103 AT clio DOT rice DOT edu> <2950-Mon20Aug2001093159+0300-eliz AT is DOT elta DOT co DOT il> <002501c12980$4c67fa80$0a02a8c0 AT acceleron> <2110-Mon20Aug2001172450+0300-eliz AT is DOT elta DOT co DOT il> <001101c12a42$7776d850$0a02a8c0 AT acceleron> <8011-Tue21Aug2001200758+0300-eliz AT is DOT elta DOT co DOT il>
Subject: Re: Fseek on STDIN problem on Win 2K
Date: Wed, 22 Aug 2001 22:03:29 +1000
MIME-Version: 1.0
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 5.50.4807.1700
X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4807.1700
Reply-To: djgpp-workers AT delorie DOT com

I hope the source code below is not too large as to cause anyone any
inconveniance or problems. Sorry in advance if it does.

> > 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.
>
> But your annotations in the source seem to indicate that the first two
> calls to seekerprint fail, while the other 3 succeed.  Do you have any
> potential explanation for this?  The calls seem identical, or am I
> missing something obvious?
This is what is so puzeling in that you are 100% correct and you are not
missing anything obvious. I still cannot explain it as it is looks like one
of those Windows bugs where you need to perform a function twice so that it
works, but in this case we ned to seek to a non zero offset and then back to
zero for it to work.

I read Charles's email about adding a lseek() in the _read() function, but a
possible better solution is to add a lseek() at the end of is_executable().
We need to check and think of how people use the STDIN so that what ever
solution is done covers all potential uses for STDIN. This may mean that we
solve the STDIN issue at hand ans keep any eye out for any new issues as the
arrise.

 > > 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)
>
> Thanks for the footwork.  However, it is hard to track what yuo
> describe, because the above output is inconsistent with the program's
> source you posted.  Could you please post a session script which shows
> output from the source of the test program you posted, including
> output from ac_get_magic?
 I have included the source code I am using below and the following is the
output without the addional 4200 call as outlined below..
DJGPP_204 D:\dj204\work\seek>seek <test
seek.c 31
seek.c 42 4200, pos = 0x0000:0000
seek.c 47 4200, fh = 0, read pos = 0x0000:0000
seek.c 58 4200, goto zero pos = 0x0000:0000
seek.c 101 0x3F00 call result flags regs.x.ax = 0x0002
seek.c 118 4200, fh = 0, fpos_high= 0, fpos_low = 0
seek.c 130 4200 results, flags = 2, fh = 0, fpos_high= 0, fpos_low = 0
seek.c 150
magic_number = 0x3231
seek.c 172 4200, flags = 0x02 pos = 0x0000:0000   Char at offset [0] = (3)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0000   Char at offset [0] = (4)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0001   Char at offset [1] = (5)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0002   Char at offset [2] = (6)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0003   Char at offset [3] = (7)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0004   Char at offset [4] = (8)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0005   Char at offset [5] = (9)
seeker = 5

> > 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?
>
> So you are saying that any lseek after reading from handle 0 isn't
> working?  That is, you can't seek a file if it was redirected into the
> standard input?
On the first lseek(TBA #1) is fails and then possible on some subseqent
lseek(0) it works. In my testing I have seen the following TBA numb ers, but
I suspect that there is some pattern which I need to look at to help resolve
this issue:
    TBA #1 with a seek of 0  fails until a subseqent seek of 0 after a seek
of non zero
    TBA #1 with a seek of 1,2,3, 4,5,6,7,8 all work

I have not had time to think of how to use this info in modifying the source
of is_executable() or other functions to work.

After I wrote the sentence above I thought that the possibel solution is to
add a seek to position 1 after the 3700 call and then to seek to zero. I
just tested this an it works. To include the change I found works change the
AC_PATCH_TEST_1  define to 1, to go back to the old code change the define
to 0.

There are other changs in the code that I am working on, for example move
the processing of the retval to just after the 3700 call so that the
additional code will not overwrite the buffer.

What do you think about this sort of solution for is_executable()?

I this is okay I could work on this patch for is_execuatable() tomorrow
night. And test it with patch to see if it works in a real world
application.

Output snippet with additonal seek is (other lines not copied):
seek.c 172 4200, flags = 0x02 pos = 0x0000:0000   Char at offset [0] = (1)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0000   Char at offset [0] = (1)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0001   Char at offset [1] = (2)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0002   Char at offset [2] = (3)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0003   Char at offset [3] = (4)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0004   Char at offset [4] = (5)
seek.c 172 4200, flags = 0x02 pos = 0x0000:0005   Char at offset [5] = (6)

> If so, either they treat handle 0 specially, or the reason is deeper.
> How about if you open a file with LFN call--does lseek after read work
> then?
I will try this tomorrow night if the proposed solution above for
is_executable() does not sound okay. If it does sound okay then this will
have to wait until the weekend.

> > (I have no idea how the STDIN handle is setup.)
>
> It isn't set up by our library, itr is simply preconnected by the
> shell whcih invoked the DJGPP program.  That is, when the DJGPP
> program starts, its handle 0 is already connected to the file, instead
> of being connected to the CON device.
Thanks for this as it explains how come I could not see this anywhere as it
is up to the shell used. I wonder if bash or 4DOS shell has work?  I will
also try this if I have time tomorrow night.


#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


#define AC_PATCH_TEST_1 1

/* 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, &regs);
    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, &regs);
    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
    /* Read 2 bytes from the file. */
    /*
            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
   */
    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, &regs);

    /* 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;
    }
    else
    {
        printf("%s %d return \n",__FILE__, __LINE__,c1,c2);
#if 1
        retval = (c1 << 8 ) + c2;
#else
        retval = _farpeekw(_dos_ds, __tb);
#endif
    }
    printf("%s %d 0x3F00 call result flags regs.x.ax = 0x%04x\n",__FILE__,
__LINE__,regs.x.ax);
#endif

#if AC_PATCH_TEST_1
    regs.x.ax = 0x4200;     /* set pointer from the beginning of file */
    regs.x.bx = fh;
    regs.x.cx = 1;    /* move to beginning of file */
    regs.x.ds = __tb_segment;
    regs.x.dx = __tb_offset;
    __dpmi_int(0x21, &regs);
    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);
#endif

    printf("%s %d 4200, fh = %d, fpos_high= %d, fpos_low = %d\n",__FILE__,
__LINE__, fh, fpos_high, fpos_low);

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

    //_read(0,&c,1);
    //printf("First char is: (%c)\n", c);  /* If given a pathname, open the
file. */

    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;

  memset(&r,0,sizeof(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 char_counter;
    int c, magic_number, seeker;
    long stdin_pos;
    struct stat st;
    FILE *pfp;

#if 1
//    seeker = aclseek(STDIN_FILENO,0,SEEK_SET);

    magic_number = ac_get_magic((const char *)0, STDIN_FILENO);
printf("magic_number = 0x%04X\n",magic_number);

    seeker = seekerprint(0);

    seeker = seekerprint(0);
    seeker = seekerprint(1);
    seeker = seekerprint(2);
    seeker = seekerprint(3);
    seeker = seekerprint(4);
    seeker = seekerprint(5);

    printf("seeker = %d\n",seeker);



#else
    if (acfstat (STDIN_FILENO, &st) != 0)
    {
      printf("Error fstat");
      return(-1);
    }

    if (S_ISREG (st.st_mode) && ((stdin_pos = ftell (stdin)) != -1))
    {
        pfp = stdin;
    }
    else
    {
      printf("Error fstmode");
      return(-1);
    }

    if (!pfp)
        return (-1);

    fseek(pfp,0,SEEK_SET);

    printf("%s %d file pos = %d\n", __FILE__, __LINE__, ftell(pfp));

    for (char_counter=0;char_counter<5;char_counter++)
    {
        c = getc (pfp);
        printf("Count = %02d, char = (%c), line = <%d>, file position=
[%d]\n", char_counter,c,__LINE__,ftell(pfp));
        if (c == EOF)
        {
            return 0;
        }
    }

    if (pfp)
        fclose(pfp);
#endif
    return(0);
}


- Raw text -


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