Subversion Repositories planix.SVN

Rev

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

#include "headers.h"

static SmbProcessResult
query(SmbSession *s, char *cmdname, char *filename, ushort infolevel, vlong cbo, Dir *d)
{
        vlong ntatime, ntmtime;
        ushort dosmode;
        ulong fnlfixupoffset;
        vlong allocsize;

        if (d == nil) {
                smbseterror(s, ERRDOS, ERRbadfile);
                return SmbProcessResultError;
        }

        switch (infolevel) {
        case SMB_QUERY_FILE_BASIC_INFO:
                ntatime = smbplan9time2time(d->atime);
                ntmtime = smbplan9time2time(d->mtime);
                dosmode = smbplan9mode2dosattr(d->mode);

                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_BASIC_INFO\n");
                translogprint(s->transaction.in.setup[0], "REPLY:\n");
                translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->atime));
                translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->mtime));
                translogprint(s->transaction.in.setup[0], "mode=0%o -> dosmode=0x%x\n", d->mode, dosmode);

                if (!smbbufferputv(s->transaction.out.data, ntmtime)
                        || !smbbufferputv(s->transaction.out.data, ntatime)
                        || !smbbufferputv(s->transaction.out.data, ntmtime)
                        || !smbbufferputv(s->transaction.out.data, ntmtime)
                        || !smbbufferputl(s->transaction.out.data, dosmode))
                        return SmbProcessResultMisc;
                break;
        case SMB_QUERY_FILE_ALL_INFO:
                ntatime = smbplan9time2time(d->atime);
                ntmtime = smbplan9time2time(d->mtime);
                dosmode = smbplan9mode2dosattr(d->mode);
                allocsize = (d->length + (1 << smbglobals.l2allocationsize) - 1) & ~((1 << smbglobals.l2allocationsize) - 1);

                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_ALL_INFO\n");
                translogprint(s->transaction.in.setup[0], "REPLY:\n");
                translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->atime));
                translogprint(s->transaction.in.setup[0], "atime=%s", ctime(d->mtime));
                translogprint(s->transaction.in.setup[0], "mode=0%o -> dosmode=0x%x\n", d->mode, dosmode);
                translogprint(s->transaction.in.setup[0], "allocsize=%d\n", allocsize);
                translogprint(s->transaction.in.setup[0], "isdir=%d\n", (d->mode & DMDIR) != 0);

                if (!smbbufferputv(s->transaction.out.data, ntmtime)
                        || !smbbufferputv(s->transaction.out.data, ntatime)
                        || !smbbufferputv(s->transaction.out.data, ntmtime)
                        || !smbbufferputv(s->transaction.out.data, ntmtime)
                        || !smbbufferputs(s->transaction.out.data, dosmode)
                        || !smbbufferputbytes(s->transaction.out.data, nil, 6)
                        || !smbbufferputv(s->transaction.out.data, allocsize)
                        || !smbbufferputv(s->transaction.out.data, d->length)
                        || !smbbufferputl(s->transaction.out.data, 0)           // hard links - ha
                        || !smbbufferputb(s->transaction.out.data, 0)           // TODO delete pending
                        || !smbbufferputb(s->transaction.out.data, (d->mode & DMDIR) != 0)
                        || !smbbufferputv(s->transaction.out.data, d->qid.path)
                        || !smbbufferputl(s->transaction.out.data, 0)           // EA size
                        || !smbbufferputl(s->transaction.out.data, (dosmode & SMB_ATTR_READ_ONLY) ? 0xa1 : 0x1a7)
                        || !smbbufferputv(s->transaction.out.data, cbo)
                        || !smbbufferputs(s->transaction.out.data, dosmode)
                        || !smbbufferputl(s->transaction.out.data, 0))  // alignment
                        return SmbProcessResultMisc;
                fnlfixupoffset = smbbufferwriteoffset(s->transaction.out.data);
                if (!smbbufferputl(s->transaction.out.data, 0)
                    || !smbbufferputstring(s->transaction.out.data, &s->peerinfo, SMB_STRING_REVPATH, filename)
                    || !smbbufferfixuprelativel(s->transaction.out.data, fnlfixupoffset))
                        return SmbProcessResultMisc;
                break;
        case SMB_QUERY_FILE_STANDARD_INFO:
                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_STANDARD_INFO\n");
                translogprint(s->transaction.in.setup[0], "REPLY:\n");
                translogprint(s->transaction.in.setup[0], "length=%lld", d->length);
                translogprint(s->transaction.in.setup[0], "isdir=%d\n", (d->qid.type & QTDIR) != 0);

                if (!smbbufferputv(s->transaction.out.data, smbl2roundupvlong(d->length, smbglobals.l2allocationsize))
                        || !smbbufferputv(s->transaction.out.data, d->length)
                        || !smbbufferputl(s->transaction.out.data, 1)
                        || !smbbufferputb(s->transaction.out.data, 0)
                        || !smbbufferputb(s->transaction.out.data, (d->qid.type & QTDIR) != 0))
                        return SmbProcessResultMisc;
                break;
        case SMB_QUERY_FILE_EA_INFO:
                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_EA_INFO\n");
                translogprint(s->transaction.in.setup[0], "REPLY:\n");
                translogprint(s->transaction.in.setup[0], "ea_len=0\n");
                if (!smbbufferputl(s->transaction.out.data, 0))
                        return SmbProcessResultMisc;
                break;
        case SMB_QUERY_FILE_STREAM_INFO:
                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FILE_STREAM_INFO\n");
                translogprint(s->transaction.in.setup[0], "REPLY: failed\n");
                /* don't do it, never will */
                goto unknownlevel;
        default:
                smblogprint(-1, "smbtrans2query%sinformation: infolevel 0x%.4ux not implemented\n", cmdname, infolevel);
        unknownlevel:
                translogprint(s->transaction.in.setup[0], "[not supported]\n");
                smbseterror(s, ERRDOS, ERRunknownlevel);
                return SmbProcessResultError;
        }
        return SmbProcessResultReply;
}

SmbProcessResult
smbtrans2querypathinformation(SmbSession *s, SmbHeader *h)
{
        SmbTree *t;
        SmbBuffer *b = nil;
        SmbProcessResult pr;
        ushort infolevel;
        Dir *d;
        char *path = nil;
        char *fullpath;

        t = smbidmapfind(s->tidmap, h->tid);
        if (t == nil) {
                smbseterror(s, ERRSRV, ERRinvtid);
                pr = SmbProcessResultError;
                goto done;
        }
        b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
        if (!smbbuffergets(b, &infolevel) || !smbbuffergetbytes(b, nil, 4)
                || !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) {
                pr = SmbProcessResultMisc;
                goto done;
        }
        translogprint(s->transaction.in.setup[0], "infolevel 0x%.4ux\n", infolevel);
        translogprint(s->transaction.in.setup[0], "path %s\n", path);
        fullpath = nil;
        smbstringprint(&fullpath, "%s%s", t->serv->path, path);
        translogprint(s->transaction.in.setup[0], "fullpath %s\n", fullpath);
        d = dirstat(fullpath);
        pr = query(s, "path", path, infolevel, 0, d);
        free(d);
        free(fullpath);
done:
        free(path);
        smbbufferfree(&b);
        return pr;
}

SmbProcessResult
smbtrans2queryfileinformation(SmbSession *s, SmbHeader *h)
{
        SmbTree *t;
        SmbFile *f;
        SmbBuffer *b = nil;
        SmbProcessResult pr;
        ushort fid;
        ushort infolevel;
        vlong o;
        Dir *d;

        t = smbidmapfind(s->tidmap, h->tid);
        if (t == nil) {
                smbseterror(s, ERRSRV, ERRinvtid);
                pr = SmbProcessResultError;
                goto done;
        }
        b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
        if (!smbbuffergets(b, &fid) || !smbbuffergets(b, &infolevel)) {
                pr = SmbProcessResultMisc;
                goto done;
        }
        translogprint(s->transaction.in.setup[0], "fid 0x%.4ux\n", fid);
        translogprint(s->transaction.in.setup[0], "infolevel 0x%.4ux\n", infolevel);
        f = smbidmapfind(s->fidmap, fid);
        if (f == nil) {
                smbseterror(s, ERRDOS, ERRbadfid);
                pr = SmbProcessResultError;
                goto done;
        }
        if(f->fd >= 0){
                o = seek(f->fd, 0, 1);
                d = dirfstat(f->fd);
        } else {
                char *fullpath = nil;

                o = 0;
                smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name);
                d = dirstat(fullpath);
                free(fullpath);
        }
        pr = query(s, "file", f->name, infolevel, o, d);
        free(d);
done:
        smbbufferfree(&b);
        return pr;
}

SmbProcessResult
smbtrans2queryfsinformation(SmbSession *s, SmbHeader *h)
{
        SmbTree *t;
        ushort infolevel;
        SmbBuffer *b;
        SmbProcessResult pr;
        ulong fixup;
        ulong vnbase;

        t = smbidmapfind(s->tidmap, h->tid);
        if (t == nil) {
                smbseterror(s, ERRSRV, ERRinvtid);
                pr = SmbProcessResultError;
                goto done;
        }
        b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
        if (!smbbuffergets(b, &infolevel)) {
        misc:
                pr = SmbProcessResultMisc;
                goto done;
        }
        pr = SmbProcessResultReply;
        switch (infolevel) {
        case SMB_INFO_ALLOCATION:
                translogprint(s->transaction.in.setup[0], "SMB_INFO_ALLOCATION\n");
                if (!smbbufferputl(s->transaction.out.data, 0)
                        || !smbbufferputl(s->transaction.out.data, 1 << (smbglobals.l2allocationsize - smbglobals.l2sectorsize))
                        || !smbbufferputl(s->transaction.out.data, 0xffffffff)
                        || !smbbufferputl(s->transaction.out.data, 0xffffffff)
                        || !smbbufferputs(s->transaction.out.data, 1 << smbglobals.l2sectorsize))
                        goto misc;
                break;
        case SMB_INFO_VOLUME:
                translogprint(s->transaction.in.setup[0], "SMB_INFO_VOLUME\n");
                if (!smbbufferputl(s->transaction.out.data, 0xdeadbeef)
                        || !smbbufferputstring(s->transaction.out.data, &s->peerinfo, 0, t->serv->name))
                        goto misc;
                break;
        case SMB_QUERY_FS_VOLUME_INFO:
                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FS_VOLUME_INFO\n");
                if (!smbbufferputv(s->transaction.out.data, 0)
                        || !smbbufferputl(s->transaction.out.data, 0xdeadbeef))
                        goto misc;
                fixup = smbbufferwriteoffset(s->transaction.out.data);
                if (!smbbufferputl(s->transaction.out.data, 0)
                        || !smbbufferputs(s->transaction.out.data, 0))
                        goto misc;
                vnbase = smbbufferwriteoffset(s->transaction.out.data);
                if (!smbbufferputstring(s->transaction.out.data, &s->peerinfo, 0, t->serv->name)
                        || !smbbufferfixupl(s->transaction.out.data, fixup,
                                smbbufferwriteoffset(s->transaction.out.data) - vnbase))
                        goto misc;
                break;
        case SMB_QUERY_FS_SIZE_INFO:
                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FS_SIZE_INFO\n");
                if (!smbbufferputv(s->transaction.out.data, 0LL)
                        || !smbbufferputv(s->transaction.out.data, 0LL)
                        || !smbbufferputl(s->transaction.out.data, 1 << (smbglobals.l2allocationsize - smbglobals.l2sectorsize))
                        || !smbbufferputl(s->transaction.out.data, 1 << smbglobals.l2sectorsize))
                        goto misc;
                break;
        case SMB_QUERY_FS_ATTRIBUTE_INFO:
                translogprint(s->transaction.in.setup[0], "SMB_QUERY_FS_ATTRIBUTE_INFO\n");
                if (!smbbufferputl(s->transaction.out.data, 3)
                        || !smbbufferputl(s->transaction.out.data, 255))
                        goto misc;
                fixup = smbbufferwriteoffset(s->transaction.out.data);
                if (!smbbufferputl(s->transaction.out.data, 0)
                        || !smbbufferputstring(s->transaction.out.data, &s->peerinfo, SMB_STRING_UNTERMINATED, smbglobals.serverinfo.nativelanman)
                        || !smbbufferfixuprelativel(s->transaction.out.data, fixup))
                        goto misc;
                break;
        default:
                smblogprint(-1, "smbtrans2queryfsinformation: infolevel 0x%.4ux not implemented\n", infolevel);
                smbseterror(s, ERRDOS, ERRunknownlevel);
                pr = SmbProcessResultError;
        }
done:
        smbbufferfree(&b);
        return pr;
}