lseek: make seeking to an offset before end of file work properly.

The direction specified by the offset was essentially reversed when calling lseek with whence==2 (seek to offset from end of file). Therefore, specifying a negative offset with whence==2 would fail, rather than seeking before the end of the file as it should.

(The ORCA/C manual is not totally clear about this behavior, but the new behavior is consistent with the POSIX spec and all other implementations I'm aware of, including traditional Unix and APW C. Note that Unix/POSIX allows seeking beyond the end of the file, but GS/OS does not.)

There are also improvements to error handling, so lseek consistently reports EINVAL for invalid offsets.
This commit is contained in:
Stephen Heumann 2022-07-14 18:33:31 -05:00
parent a2bca0df04
commit 505f1c2804
1 changed files with 34 additions and 21 deletions

View File

@ -380,43 +380,56 @@ mark equ 1 new file mark
tax tax
lda >files,X lda >files,X
bne lb2 bne lb2
lb1 lda #EBADF bad refnum error lb1 bra lb4a bad refnum error
sta >errno
bra lb4
lb2 sta >smRefnum set the file refnum lb2 sta >smRefnum set the file refnum
sta >gmRefnum sta >gmRefnum
lda whence convert from UNIX whence to GS/OS base lda whence convert from UNIX whence to GS/OS base
beq lb3 cmp #SEEK_SET if whence == 0 (SEEK_SET)
eor #$0003 bne lb2a
cmp #4 lda offset+2 if offset is negative
bge lb2a bmi lb4 fail with EINVAL
cmp #2 lda #0 set mark to offset
bne lb3
sta >smBase
lda offset+2
bpl lb3a
sub4 #0,offset,offset
lda #3
bra lb3 bra lb3
lb2a lda #EINVAL invalid whence flag lb2a cmp #SEEK_END else if whence == 2 (SEEK_END)
sta >errno bne lb2c
bra lb4 lda offset+2 if offset > 0
bmi lb2b
ora offset
bne lb4 fail with EINVAL
lb2b sub4 #0,offset,offset negate offset
lda #1 set mark to EOF - offset
bra lb3
lb2c cmp #SEEK_CUR else if whence == 1 (SEEK_CUR)
bne lb4
lda offset if offset is positive or 0
bmi lb2d
lda #2 set mark to old mark + offset
bra lb3 else
lb2d sub4 #0,offset,offset negate offset
lda #3 set mark to old mark - offset
lb3 sta >smBase save the base parameter lb3 sta >smBase save the base parameter
lb3a lda offset set the displacement lb3a lda offset set the displacement
sta >smDisplacement sta >smDisplacement
lda offset+2 lda offset+2
sta >smDisplacement+2 sta >smDisplacement+2
OSSet_Mark smRec set the file mark OSSet_Mark smRec set the file mark
bcs lb1 bcc lb5
OSGet_Mark gmRec get the new mark cmp #$4D out of range error => fail with EINVAL
bcs lb1 bne lb4a
lb4 lda #EINVAL
bra lb4b
lb4a lda #EBADF bad refnum error
lb4b sta >errno
bra lb6
lb5 OSGet_Mark gmRec get the new mark
bcs lb4a
lda >gmDisplacement lda >gmDisplacement
sta mark sta mark
lda >gmDisplacement+2 lda >gmDisplacement+2
sta mark+2 sta mark+2
lb4 creturn 4:mark lb6 creturn 4:mark
smRec dc i'3' SetMark record smRec dc i'3' SetMark record
smRefnum ds 2 smRefnum ds 2