xref: /plan9/sys/src/libbio/bseek.c (revision 58db92f49907d8fad4b51ea9739d73b48e4ebd9d)
13e12c5d1SDavid du Colombier #include	<u.h>
23e12c5d1SDavid du Colombier #include	<libc.h>
33e12c5d1SDavid du Colombier #include	<bio.h>
43e12c5d1SDavid du Colombier 
57dd7cddfSDavid du Colombier vlong
Bseek(Biobufhdr * bp,vlong offset,int base)67dd7cddfSDavid du Colombier Bseek(Biobufhdr *bp, vlong offset, int base)
73e12c5d1SDavid du Colombier {
87dd7cddfSDavid du Colombier 	vlong n, d;
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier 	switch(bp->state) {
113e12c5d1SDavid du Colombier 	default:
123e12c5d1SDavid du Colombier 		fprint(2, "Bseek: unknown state %d\n", bp->state);
13219b2ee8SDavid du Colombier 		return Beof;
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier 	case Bracteof:
163e12c5d1SDavid du Colombier 		bp->state = Bractive;
17219b2ee8SDavid du Colombier 		bp->icount = 0;
18219b2ee8SDavid du Colombier 		bp->gbuf = bp->ebuf;
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier 	case Bractive:
21219b2ee8SDavid du Colombier 		n = offset;
223e12c5d1SDavid du Colombier 		if(base == 1) {
23219b2ee8SDavid du Colombier 			n += Boffset(bp);
243e12c5d1SDavid du Colombier 			base = 0;
253e12c5d1SDavid du Colombier 		}
26219b2ee8SDavid du Colombier 
27219b2ee8SDavid du Colombier 		/*
28219b2ee8SDavid du Colombier 		 * try to seek within buffer
29219b2ee8SDavid du Colombier 		 */
30219b2ee8SDavid du Colombier 		if(base == 0) {
31*58db92f4SDavid du Colombier 			/*
32*58db92f4SDavid du Colombier 			 * if d is too large for an int, icount may wrap,
33*58db92f4SDavid du Colombier 			 * so we need to ensure that icount hasn't wrapped
34*58db92f4SDavid du Colombier 			 * and points within the buffer's valid data.
35*58db92f4SDavid du Colombier 			 */
36219b2ee8SDavid du Colombier 			d = n - Boffset(bp);
37219b2ee8SDavid du Colombier 			bp->icount += d;
38*58db92f4SDavid du Colombier 			if(d <= bp->bsize && bp->icount <= 0 &&
39*58db92f4SDavid du Colombier 			    bp->ebuf - bp->gbuf >= -bp->icount)
40219b2ee8SDavid du Colombier 				return n;
41219b2ee8SDavid du Colombier 		}
42219b2ee8SDavid du Colombier 
43219b2ee8SDavid du Colombier 		/*
44219b2ee8SDavid du Colombier 		 * reset the buffer
45219b2ee8SDavid du Colombier 		 */
46219b2ee8SDavid du Colombier 		n = seek(bp->fid, n, base);
473e12c5d1SDavid du Colombier 		bp->icount = 0;
48219b2ee8SDavid du Colombier 		bp->gbuf = bp->ebuf;
493e12c5d1SDavid du Colombier 		break;
503e12c5d1SDavid du Colombier 
513e12c5d1SDavid du Colombier 	case Bwactive:
523e12c5d1SDavid du Colombier 		Bflush(bp);
533e12c5d1SDavid du Colombier 		n = seek(bp->fid, offset, base);
543e12c5d1SDavid du Colombier 		break;
553e12c5d1SDavid du Colombier 	}
563e12c5d1SDavid du Colombier 	bp->offset = n;
573e12c5d1SDavid du Colombier 	return n;
583e12c5d1SDavid du Colombier }
59