Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "headers.h"

#define BUFFER 1
#define STRUCT 2
#define PUSHED 4

struct SmbBuffer {
        uchar *buf;
        ulong realmaxlen;
        ulong maxlen;
        ulong rn;
        ulong wn;
        ulong savewn;
        int flags;
};

void
smbbufferreset(SmbBuffer *s)
{
        if (s == nil)
                return;
        s->rn = 0;
        s->wn = 0;
        s->flags &= ~PUSHED;
}

void
smbbuffersetbuf(SmbBuffer *s, void *p, ulong maxlen)
{
        s->realmaxlen = s->maxlen = maxlen;
        if (s->buf) {
                if (s->flags & BUFFER)
                        free(s->buf);
                s->buf = nil;
        }
        s->flags &= ~BUFFER;
        if (p)
                s->buf = p;
        else {
                s->buf = smbemalloc(maxlen);
                s->flags |= BUFFER;
        }
        smbbufferreset(s);
}

SmbBuffer *
smbbufferinit(void *base, void *bdata, ulong blen)
{
        SmbBuffer *b;
        b = smbemalloc(sizeof(*b));
        b->buf = base;
        b->flags = STRUCT;      
        b->rn = (uchar *)bdata - (uchar *)base;
        b->wn = b->rn + blen;
        b->realmaxlen = b->maxlen = b->wn;
        return b;
}

int
smbbufferalignl2(SmbBuffer *s, int al2)
{
        ulong mask, newn;
        mask = (1 << al2) - 1;
        newn = (s->wn + mask) & ~mask;
        if (newn != s->wn) {
                if (newn > s->maxlen)
                        return 0;
                s->wn = newn;
        }
        return 1;
}

int
smbbufferputb(SmbBuffer *s, uchar b)
{
        if (s->wn >= s->maxlen)
                return 0;
        s->buf[s->wn++] = b;
        return 1;
}

ulong
smbbufferspace(SmbBuffer *sess)
{
        return sess->maxlen - sess->wn;
}

int
smbbufferoffsetputs(SmbBuffer *sess, ulong offset, ushort s)
{
        if (offset + 2 > sess->wn)
                return 0;
        smbhnputs(sess->buf + offset, s);
        return 1;
}

int
smbbufferputs(SmbBuffer *sess, ushort s)
{
        if (sess->wn + sizeof(ushort) > sess->maxlen)
                return 0;
        smbhnputs(sess->buf + sess->wn, s);
        sess->wn += sizeof(ushort);
        return 1;
}

int
smbbufferputl(SmbBuffer *s, ulong l)
{
        if (s->wn + sizeof(ulong) > s->maxlen)
                return 0;
        smbhnputl(s->buf + s->wn, l);
        s->wn += sizeof(ulong);
        return 1;
}

int
smbbufferputv(SmbBuffer *s, vlong v)
{
        if (s->wn + sizeof(vlong) > s->maxlen)
                return 0;
        smbhnputv(s->buf + s->wn, v);
        s->wn += sizeof(vlong);
        return 1;
}

int
smbbufferputbytes(SmbBuffer *s, void *data, ulong datalen)
{
        if (s->wn + datalen > s->maxlen)
                return 0;
        if (data)
                memcpy(s->buf + s->wn, data, datalen);
        s->wn += datalen;
        return 1;
}

int
smbbufferputstring(SmbBuffer *b, SmbPeerInfo *p, ulong flags, char *string)
{
        int n = smbstringput(p, flags, b->buf, b->wn, b->maxlen, string);
        if (n <= 0)
                return 0;
        b->wn += n;
        return 1;
}

int
smbbufferputstrn(SmbBuffer *s, char *string, int size, int upcase)
{
        int n = smbstrnput(s->buf, s->wn, s->maxlen, string, size, upcase);
        if (n <= 0)
                return 0;
        s->wn += n;
        return 1;
}

ulong
smbbufferwriteoffset(SmbBuffer *s)
{
        return s->wn;
}

ulong
smbbufferwritemaxoffset(SmbBuffer *s)
{
        return s->maxlen;
}

ulong
smbbufferreadoffset(SmbBuffer *s)
{
        return s->rn;
}

void *
smbbufferreadpointer(SmbBuffer *s)
{
        return s->buf + s->rn;
}

void *
smbbufferwritepointer(SmbBuffer *s)
{
        return s->buf + s->wn;
}

ulong
smbbufferwritespace(SmbBuffer *b)
{
        return b->maxlen - b->wn;
}

SmbBuffer *
smbbuffernew(ulong maxlen)
{
        SmbBuffer *b;
        b = smbemalloc(sizeof(SmbBuffer));
        b->buf = smbemalloc(maxlen);
        b->realmaxlen = b->maxlen = maxlen;
        b->rn = 0;
        b->wn = 0;
        b->flags = STRUCT | BUFFER;
        return b;
}

void
smbbufferfree(SmbBuffer **bp)
{
        SmbBuffer *b = *bp;
        if (b) {
                if (b->flags & BUFFER) {
                        free(b->buf);
                        b->buf = nil;
                        b->flags &= ~BUFFER;
                }
                if (b->flags & STRUCT)
                        free(b);
                *bp = nil;
        }
}

uchar *
smbbufferbase(SmbBuffer *b)
{
        return b->buf;
}

int
smbbuffergetbytes(SmbBuffer *b, void *buf, ulong len)
{
        if (b->rn + len > b->wn)
                return 0;
        if (buf)
                memcpy(buf, b->buf + b->rn, len);
        b->rn += len;
        return 1;
}

void
smbbuffersetreadlen(SmbBuffer *b, ulong len)
{
        b->wn = b->rn + len;
}

int
smbbuffertrimreadlen(SmbBuffer *b, ulong len)
{
        if (b->rn + len > b->wn)
                return 0;
        else if (b->rn + len < b->wn)
                b->wn = b->rn + len;
        return 1;
}

int
smbbuffergets(SmbBuffer *b, ushort *sp)
{
        if (b->rn + 2 > b->wn)
                return 0;
        *sp = smbnhgets(b->buf + b->rn);
        b->rn += 2;
        return 1;
}

int
smbbuffergetstrn(SmbBuffer *b, ushort size, char **sp)
{
        uchar *np;
        if (size > b->wn - b->rn)
                return 0;
        np = memchr(b->buf + b->rn, 0, size);
        if (np == nil)
                return 0;
        *sp = strdup((char *)b->buf + b->rn);
        b->rn += size;
        return 1;
}

int
smbbuffergetstr(SmbBuffer *b, ulong flags, char **sp)
{
        int c;
        char *p;
        uchar *np;

        np = memchr(b->buf + b->rn, 0, b->wn - b->rn);
        if (np == nil)
                return 0;
        *sp = strdup((char *)b->buf + b->rn);
        for (p = *sp; *p != 0; p++) {
                c = *p;
                if (c >= 'a' && c <= 'z' && (flags & SMB_STRING_UPCASE))
                        *p = toupper(c);
                else if (c == '/' && (flags & SMB_STRING_REVPATH))
                        *p = '\\';
                else if (c == '\\' && (flags & SMB_STRING_PATH))
                        *p = '/';
                else if (smbglobals.convertspace){
                        if (c == 0xa0 && (flags & SMB_STRING_REVPATH))
                                *p = ' ';
                        else if (c == ' ' && (flags & SMB_STRING_PATH))
                                *p = 0xa0;
                }
        }
        b->rn = np - b->buf + 1;
        return 1;
}

int
smbbuffergetstrinline(SmbBuffer *b, char **sp)
{
        uchar *np;
        np = memchr(b->buf + b->rn, 0, b->wn - b->rn);
        if (np == nil)
                return 0;
        *sp = (char *)b->buf + b->rn;
        b->rn = np - b->buf + 1;
        return 1;
}

int
smbbuffergetucs2(SmbBuffer *b, ulong flags, char **sp)
{
        uchar *bdata = b->buf + b->rn;
        uchar *edata = b->buf + b->wn;
        Rune r;
        int l;
        char *p, *q;
        uchar *savebdata;
        int first;

        l = 0;
        if ((flags & SMB_STRING_UNALIGNED) == 0 && (bdata - b->buf) & 1)
                bdata++;
        savebdata = bdata;
        first = 1;
        do {
                if (bdata + 2 > edata) {
                        l++;
                        break;
                }
                r = smbnhgets(bdata); bdata += 2;
                if (first && (flags & SMB_STRING_PATH) && r != '\\')
                        l++;
                first = 0;
                if (flags & SMB_STRING_CONVERT_MASK)
                        r = smbruneconvert(r, flags);
                l += runelen(r);
        } while (r != 0);
        p = smbemalloc(l);
        bdata = savebdata;
        q = p;
        first = 1;
        do {
                if (bdata + 2 > edata) {
                        *q = 0;
                        break;
                }
                r = smbnhgets(bdata); bdata += 2;
                if (first && (flags & SMB_STRING_PATH) && r != '\\')
                        *q++ = '/';
                first = 0;
                if (flags & SMB_STRING_CONVERT_MASK)
                        r = smbruneconvert(r, flags);
                q += runetochar(q, &r);
        } while (r != 0);
        b->rn = bdata - b->buf;
        *sp = p;
        return 1;
}

int
smbbuffergetstring(SmbBuffer *b, SmbHeader *h, ulong flags, char **sp)
{
        if (flags & SMB_STRING_UNICODE)
                return smbbuffergetucs2(b, flags, sp);
        else if (flags & SMB_STRING_ASCII)
                return smbbuffergetstr(b, flags, sp);
        else if (h->flags2 & SMB_FLAGS2_UNICODE)
                return smbbuffergetucs2(b, flags, sp);
        else
                return smbbuffergetstr(b, flags, sp);
}

void *
smbbufferpointer(SmbBuffer *b, ulong offset)
{
        return b->buf + offset;
}

int
smbbuffergetb(SmbBuffer *b, uchar *bp)
{
        if (b->rn < b->wn) {
                *bp = b->buf[b->rn++];
                return 1;
        }
        return 0;
}

int
smbbuffergetl(SmbBuffer *b, ulong *lp)
{
        if (b->rn + 4 <= b->wn) {
                *lp = smbnhgetl(b->buf + b->rn);
                b->rn += 4;
                return 1;
        }
        return 0;
}

int
smbbuffergetv(SmbBuffer *b, vlong *vp)
{
        if (b->rn + 8 <= b->wn) {
                *vp = smbnhgetv(b->buf + b->rn);
                b->rn += 8;
                return 1;
        }
        return 0;
}

ulong
smbbufferreadspace(SmbBuffer *b)
{
        return b->wn - b->rn;
}

void
smbbufferwritelimit(SmbBuffer *b, ulong limit)
{
        if (b->rn + limit < b->maxlen)
                b->maxlen = b->rn + limit;
}

int
smbbufferreadskipto(SmbBuffer *b, ulong offset)
{
        if (offset < b->rn || offset >= b->wn)
                return 0;
        b->rn = offset;
        return 1;
}

int
smbbufferpushreadlimit(SmbBuffer *b, ulong limit)
{
        if (b->flags & PUSHED)
                return 0;
        if (limit > b->wn || limit < b->rn)
                return 0;
        b->savewn = b->wn;
        b->wn = limit;
        b->flags |= PUSHED;
        return 1;
}

int
smbbufferpopreadlimit(SmbBuffer *b)
{
        if ((b->flags & PUSHED) == 0)
                return 0;
        b->wn = b->savewn;
        b->flags &= ~PUSHED;
        return 1;
}

int
smbbufferwritebackup(SmbBuffer *b, ulong offset)
{
        if (offset >= b->rn && offset <= b->wn) {
                b->wn = offset;
                return 1;
        }
        return 0;
}

int
smbbufferreadbackup(SmbBuffer *b, ulong offset)
{
        if (offset <= b->rn) {
                b->rn = offset;
                return 1;
        }
        return 0;
}

int
smbbufferfixuprelatives(SmbBuffer *b, ulong fixupoffset)
{
        ulong fixval;
        if (fixupoffset < b->rn || fixupoffset > b->wn - 2)
                return 0;
        fixval = b->wn - fixupoffset - 2;
        if (fixval > 65535)
                return 0;
        smbhnputs(b->buf + fixupoffset, fixval);
        return 1;
}

int
smbbufferfixuprelativel(SmbBuffer *b, ulong fixupoffset)
{
        ulong fixval;
        if (fixupoffset < b->rn || fixupoffset > b->wn - 4)
                return 0;
        fixval = b->wn - fixupoffset - 4;
        smbhnputl(b->buf + fixupoffset, fixval);
        return 1;
}

int
smbbufferfixupabsolutes(SmbBuffer *b, ulong fixupoffset)
{
        if (fixupoffset < b->rn || fixupoffset > b->wn - 2)
                return 0;
        if (b->wn > 65535)
                return 0;
        smbhnputs(b->buf + fixupoffset, b->wn);
        return 1;
}

int
smbbufferfixupl(SmbBuffer *b, ulong fixupoffset, ulong fixupval)
{
        if (fixupoffset < b->rn || fixupoffset > b->wn - 4)
                return 0;
        smbhnputl(b->buf + fixupoffset, fixupval);
        return 1;
}

int
smbbufferfixupabsolutel(SmbBuffer *b, ulong fixupoffset)
{
        if (fixupoffset < b->rn || fixupoffset > b->wn - 2)
                return 0;
        smbhnputl(b->buf + fixupoffset, b->wn);
        return 1;
}

int
smbbufferfixuprelativeinclusivel(SmbBuffer *b, ulong fixupoffset)
{
        if (fixupoffset < b->rn || fixupoffset > b->wn - 4)
                return 0;
        smbhnputl(b->buf + fixupoffset, b->wn - fixupoffset);
        return 1;
}

int
smbbufferfill(SmbBuffer *b, uchar val, ulong len)
{
        if (b->maxlen - b->wn < len)
                return 0;
        memset(b->buf + b->wn, val, len);
        b->wn += len;
        return 1;
}

int
smbbufferoffsetgetb(SmbBuffer *b, ulong offset, uchar *bp)
{
        if (offset >= b->rn && offset + 1 <= b->wn) {
                *bp = b->buf[b->rn + offset];
                return 1;
        }
        return 0;
}

int
smbbuffercopy(SmbBuffer *to, SmbBuffer *from, ulong amount)
{
        if (smbbufferreadspace(from) < amount)
                return 0;
        if (smbbufferputbytes(to, smbbufferreadpointer(from), amount)) {
                assert(smbbuffergetbytes(from, nil, amount));
                return 1;
        }
        return 0;
}

int
smbbufferoffsetcopystr(SmbBuffer *b, ulong offset, char *buf, int buflen, int *lenp)
{
        uchar *np;
        if (offset < b->rn || offset >= b->wn)
                return 0;
        np = memchr(b->buf + offset, 0, b->wn - offset);
        if (np == nil)
                return 0;
        *lenp = np - (b->buf + offset) + 1;
        if (*lenp > buflen)
                return 0;
        memcpy(buf, b->buf + offset, *lenp);
        return 1;
}