/*
 * This file is part of the UCB release of Plan 9. It is subject to the license
 * terms in the LICENSE file found in the top-level directory of this
 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
 * part of the UCB release of Plan 9, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms contained
 * in the LICENSE file.
 */
#define PORTABLE_SYSCALLS
#include <u.h>
#include <libc.h>
#include <9P2000.h>

static
int32_t
dirpackage(uint8_t *buf, int32_t ts, Dir **d)
{
	char *s;
	int32_t ss, i, n, nn, m;

	*d = nil;
	if(ts <= 0)
		return 0;

	/*
	 * first find number of all stats, check they look like stats, & size all associated strings
	 */
	ss = 0;
	n = 0;
	for(i = 0; i < ts; i += m){
		m = BIT16SZ + GBIT16(&buf[i]);
		if(statcheck(&buf[i], m) < 0)
			break;
		ss += m;
		n++;
	}

	if(i != ts)
		return -1;

	*d = jehanne_malloc(n * sizeof(Dir) + ss);
	if(*d == nil)
		return -1;

	/*
	 * then convert all buffers
	 */
	s = (char*)*d + n * sizeof(Dir);
	nn = 0;
	for(i = 0; i < ts; i += m){
		m = BIT16SZ + GBIT16((uint8_t*)&buf[i]);
		if(nn >= n || jehanne_convM2D(&buf[i], m, *d + nn, s) != m){
			jehanne_free(*d);
			*d = nil;
			return -1;
		}
		nn++;
		s += m;
	}

	return nn;
}

int32_t
jehanne_dirread(int fd, Dir **d)
{
	uint8_t *buf;
	int32_t ts;

	buf = jehanne_malloc(DIRMAX);
	if(buf == nil)
		return -1;
	ts = read(fd, buf, DIRMAX);
	if(ts >= 0)
		ts = dirpackage(buf, ts, d);
	jehanne_free(buf);
	return ts;
}

int32_t
jehanne_dirreadall(int fd, Dir **d)
{
	uint8_t *buf, *nbuf;
	int32_t n, ts;

	buf = nil;
	ts = 0;
	for(;;){
		nbuf = jehanne_realloc(buf, ts+DIRMAX);
		if(nbuf == nil){
			jehanne_free(buf);
			return -1;
		}
		buf = nbuf;
		n = read(fd, buf+ts, DIRMAX);
		if(n <= 0)
			break;
		ts += n;
	}
	if(ts >= 0)
		ts = dirpackage(buf, ts, d);
	jehanne_free(buf);
	if(ts == 0 && n < 0)
		return -1;
	return ts;
}
