Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include "headers.h"

static int
getlock(SmbBuffer *b, int large, ushort *pidp, uvlong *offsetp, uvlong *lengthp)
{
        ulong ohigh, olow;
        ulong lhigh, llow;
        if (!smbbuffergets(b, pidp))
                return 0;
        if (large && !smbbuffergetbytes(b, nil, 2))
                return 0;
        if (large) {
                if (!smbbuffergetl(b, &ohigh) || !smbbuffergetl(b, &olow)
                        || !smbbuffergetl(b, &lhigh) || !smbbuffergetl(b, &llow))
                        return 0;
                *offsetp = ((uvlong)ohigh << 32) | olow;
                *lengthp = ((uvlong)lhigh << 32) | llow;
                return 1;
        }
        if (!smbbuffergetl(b, &olow) || !smbbuffergetl(b, &llow))
                return 0;
        *offsetp = olow;
        *lengthp = llow;
        return 1;
}

SmbProcessResult
smbcomlockingandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
{
        uchar andxcommand;
        ushort andxoffset;
        ulong andxoffsetfixup;
        ushort fid;
        uchar locktype;
        uchar oplocklevel;
        ulong timeout;
        ushort numberofunlocks;
        ushort numberoflocks;
        SmbTree *t;
        SmbFile *f;
        int l;
        SmbProcessResult pr;
        ulong backupoffset;
        int large;

        if (!smbcheckwordcount("comlockingandx", h, 8))
                return SmbProcessResultFormat;

        andxcommand = *pdata++;
        pdata++;
        andxoffset = smbnhgets(pdata); pdata += 2;
        fid = smbnhgets(pdata); pdata += 2;
        locktype = *pdata++;
        oplocklevel = *pdata++;
        timeout = smbnhgetl(pdata); pdata += 4;
        numberofunlocks = smbnhgets(pdata); pdata += 2;
        numberoflocks = smbnhgets(pdata);
        smblogprint(h->command, "smbcomlockingandx: fid 0x%.4ux locktype 0x%.2ux oplocklevel 0x%.2ux timeout %lud numberofunlocks %d numberoflocks %ud\n",
                fid, locktype, oplocklevel, timeout, numberofunlocks, numberoflocks);
        large = locktype & 0x10;
        locktype &= ~0x10;
        if (locktype != 0 || oplocklevel != 0) {
                smblogprint(-1, "smbcomlockingandx: locktype 0x%.2ux unimplemented\n", locktype);
                return SmbProcessResultUnimp;
        }
        if (oplocklevel != 0) {
                smblogprint(-1, "smbcomlockingandx: oplocklevel 0x%.2ux unimplemented\n", oplocklevel);
                return SmbProcessResultUnimp;
        }
        t = smbidmapfind(s->tidmap, h->tid);
        if (t == nil) {
                smbseterror(s, ERRSRV, ERRinvtid);
        error:
                return SmbProcessResultError;
        }
        f = smbidmapfind(s->fidmap, fid);
        if (f == nil) {
                smbseterror(s, ERRDOS, ERRbadfid);
                goto error;
        }
        backupoffset = smbbufferreadoffset(b);
        for (l = 0; l < numberofunlocks; l++) {
                ushort pid;
                uvlong offset;
                uvlong length;
                if (!getlock(b, large, &pid, &offset, &length)) {
                        pr = SmbProcessResultFormat;
                        goto done;
                }
                smblogprint(h->command, "smbcomlockingandx: unlock pid 0x%.4ux offset %llud length %llud\n",
                        pid, offset, length);
                smbsharedfileunlock(f->sf, s, h->pid, offset, offset + length);
        }
        for (l = 0; l < numberoflocks; l++) {
                ushort pid;
                uvlong offset;
                uvlong length;
                if (!getlock(b, large, &pid, &offset, &length)) {
                        pr = SmbProcessResultFormat;
                        goto done;
                }
                smblogprint(h->command, "smbcomlockingandx: lock pid 0x%.4ux offset %llud length %llud\n",
                        pid, offset, length);
                if (!smbsharedfilelock(f->sf, s, h->pid, offset, offset + length))
                        break;
        }
        if (l < numberoflocks) {
                ushort i;
                ushort pid;
                uvlong offset;
                uvlong length;
                smbbufferreadbackup(b, backupoffset);
                for (i  = 0; i < l; i++) {
                        assert(getlock(b, large, &pid, &offset, &length));
                        smbsharedfileunlock(f->sf, s, h->pid, offset, offset + length);
                }
                smbseterror(s, ERRDOS, ERRlock);
                goto error;
        }
        h->wordcount = 2;
        if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup)
                || !smbbufferputs(s->response, 0)) {    // bytecount 0
                pr = SmbProcessResultMisc;
                goto done;
        }
        if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
                pr = smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
        else
                pr = SmbProcessResultReply;
done:
        return pr;
}