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" To: "Eli Zaretskii" Cc: , 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 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit 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 > 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 #include #include #include #include #include #include #include #include #include #include #include #include #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, ®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 /* 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, ®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; } 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, ®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); #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, ®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); //_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); }