Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include "lib.h"
#include <string.h>
#include <stdlib.h>
#include "sys9.h"
#include "dir.h"

static int
statcheck(uchar *buf, uint nbuf)
{
        uchar *ebuf;
        int i;

        ebuf = buf + nbuf;

        buf += STATFIXLEN - 4 * BIT16SZ;

        for(i = 0; i < 4; i++){
                if(buf + BIT16SZ > ebuf)
                        return -1;
                buf += BIT16SZ + GBIT16(buf);
        }

        if(buf != ebuf)
                return -1;

        return 0;
}

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

        if(ts == 0){
                *d = nil;
                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 = 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((uchar*)&buf[i]);
                if(nn >= n || _convM2D(&buf[i], m, *d + nn, s) != m){
                        free(*d);
                        return -1;
                }
                nn++;
                s += m;
        }

        return nn;
}

long
_dirread(int fd, Dir **d)
{
        uchar *buf;
        long ts;

        buf = malloc(DIRMAX);
        if(buf == nil)
                return -1;
        ts = _READ(fd, buf, DIRMAX);
        if(ts >= 0)
                ts = dirpackage(buf, ts, d);
        free(buf);
        return ts;
}

long
_dirreadall(int fd, Dir **d)
{
        uchar *buf, *nbuf;
        long n, ts;

        buf = nil;
        ts = 0;
        for(;;){
                nbuf = realloc(buf, ts+DIRMAX);
                if(nbuf == nil){
                        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);
        free(buf);
        return ts;
}