Example #1
0
static int32_t
read(int ispread, int fd, void *p, int32_t n, int64_t off)
{
	Proc *up = externup();
	int32_t nn, nnn;
	Chan *c;

	p = validaddr(p, n, 1);

	c = fdtochan(fd, OREAD, 1, 1);

	if(waserror()){
		cclose(c);
		nexterror();
	}

	/*
	 * The offset is passed through on directories, normally.
	 * Sysseek complains, but pread is used by servers like exportfs,
	 * that shouldn't need to worry about this issue.
	 *
	 * Notice that c->devoffset is the offset that c's dev is seeing.
	 * The number of bytes read on this fd (c->offset) may be different
	 * due to rewritings in mountfix.
	 */
	if(ispread){
		if(off == ~0LL){	/* use and maintain channel's offset */
			off = c->offset;
			ispread = 0;
		}
	}
	else
		off = c->offset;
	if(c->qid.type & QTDIR){
		/*
		 * Directory read:
		 * rewind to the beginning of the file if necessary;
		 * try to fill the buffer via mountrockread;
		 * clear ispread to always maintain the Chan offset.
		 */
		if(off == 0LL){
			if(!ispread){
				c->offset = 0;
				c->devoffset = 0;
			}
			mountrewind(c);
			unionrewind(c);
		}

		if(!mountrockread(c, p, n, &nn)){
			if(c->umh)
				nn = unionread(c, p, n);
			else{
				if(off != c->offset)
					error(Edirseek);
				nn = c->dev->read(c, p, n, c->devoffset);
			}
		}
		nnn = mountfix(c, p, nn, n);

		ispread = 0;
	}
	else
		nnn = nn = c->dev->read(c, p, n, off);

	if(!ispread){
		lock(&c->r.l);
		c->devoffset += nn;
		c->offset += nnn;
		unlock(&c->r.l);
	}

	poperror();
	cclose(c);

	return nnn;
}
Example #2
0
static long
read(ulong *arg, vlong *offp)
{
	long n, nn, nnn;
	uchar *p;
	Chan *c;
	vlong off;

	n = arg[2];
	validaddr(arg[1], n, 1);
	p = (void*)arg[1];
	c = fdtochan(arg[0], OREAD, 1, 1);

	if(waserror()){
		cclose(c);
		nexterror();
	}

	/*
	 * The offset is passed through on directories, normally.
	 * Sysseek complains, but pread is used by servers like exportfs,
	 * that shouldn't need to worry about this issue.
	 *
	 * Notice that c->devoffset is the offset that c's dev is seeing.
	 * The number of bytes read on this fd (c->offset) may be different
	 * due to rewritings in rockfix.
	 */
	if(offp == nil)	/* use and maintain channel's offset */
		off = c->offset;
	else
		off = *offp;
	if(off < 0)
		error(Enegoff);

	if(off == 0){	/* rewind to the beginning of the directory */
		if(offp == nil){
			c->offset = 0;
			c->devoffset = 0;
		}
		mountrewind(c);
		unionrewind(c);
	}

	if(c->qid.type & QTDIR){
		if(mountrockread(c, p, n, &nn)){
			/* do nothing: mountrockread filled buffer */
		}else if(c->umh)
			nn = unionread(c, p, n);
		else{
			if(off != c->offset)
				error(Edirseek);
			nn = devtab[c->type]->read(c, p, n, c->devoffset);
		}
		nnn = mountfix(c, p, nn, n);
	}else
		nnn = nn = devtab[c->type]->read(c, p, n, off);

	lock(c);
	c->devoffset += nn;
	c->offset += nnn;
	unlock(c);

	poperror();
	cclose(c);

	return nnn;
}