/* ----------------------------------------------
*/
#include "afpcmd.h"
#include "afphelper.h"
#include "testhelper.h"

/* -------------------------- */
static void test_bytelock_ext(uint16_t vol, char *name, int type)
{
    int fork;
    int fork1;
    uint16_t bitmap = 0;
    int len = (type == OPENFORK_RSCS) ? (1 << FILPBIT_RFLEN) : (1 << FILPBIT_DFLEN);

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_nottested();
        goto fin;
    }

    fork = FPOpenFork(Conn, vol, type, bitmap, DIRDID_ROOT, name,
                      OPENACC_WR | OPENACC_RD);

    if (!fork) {
        test_failed();
        goto fin;
    }

    if (FPByteLock_ext(Conn, fork, 0, 0 /* set */, 0, 100)) {
        test_failed();
    } else if (FPByteLock_ext(Conn, fork, 0, 1 /* clear */, 0, 100)) {
        test_failed();
    }

    FAIL(FPByteLock_ext(Conn, fork, 0, 0 /* set */, 0, 100))
    FAIL(htonl(AFPERR_PARAM) != FPByteLock_ext(Conn, fork, 0, 0, -1, 75))
    FAIL(htonl(AFPERR_NORANGE) != FPByteLock_ext(Conn, fork, 0, 1 /* clear */, 0,
            75))
    FAIL(htonl(AFPERR_RANGEOVR) != FPByteLock_ext(Conn, fork, 0, 0, 80 /* set */,
            100))
    fork1 = FPOpenFork(Conn, vol, type, bitmap, DIRDID_ROOT, name,
                       OPENACC_WR | OPENACC_RD);

    if (!fork1) {
        test_failed();
    } else {
        FAIL(htonl(AFPERR_LOCK) != FPByteLock_ext(Conn, fork1, 0, 0 /* set */, 20, 60))
        FAIL(FPSetForkParam(Conn, fork, len, 50))
        FAIL(FPSetForkParam(Conn, fork1, len, 60))
        FAIL(htonl(AFPERR_LOCK) != FPRead(Conn, fork1, 0, 40, Data))
        FAIL(htonl(AFPERR_LOCK) != FPWrite(Conn, fork1, 10, 40, Data, 0))
        FAIL(FPCloseFork(Conn, fork1))
    }

    /* fin */
    /* Netatalk 2 doesn't drop locks when a fork is closed, 3 does */
    FPByteLock_ext(Conn, fork, 0, 1 /* clear */, 0, 100);
    FAIL(htonl(AFPERR_NORANGE) != FPByteLock_ext(Conn, fork, 0, 1 /* clear */, 0,
            50))
    FAIL(FPSetForkParam(Conn, fork, len, 200))

    if (FPByteLock_ext(Conn, fork, 1 /* end */, 0 /* set */, 0, 100)) {
        test_failed();
    } else if (FPByteLock_ext(Conn, fork, 0, 1 /* clear */, 200, 100)) {
        test_failed();
    }

    if (FPByteLock_ext(Conn, fork, 0 /* end */, 0 /* set */, 0, -1)) {
        test_failed();
    } else if (FPByteLock_ext(Conn, fork, 0, 1 /* clear */, 0, -1)) {
        test_failed();
    }

    FAIL(htonl(AFPERR_PARAM) != FPByteLock_ext(Conn, fork, 0 /* start */,
            0 /* set */, 0, 0))
    FAIL(htonl(AFPERR_PARAM) != FPByteLock_ext(Conn, fork, 0 /* start */,
            0 /* set */, 0, -2))
    FAIL(FPCloseFork(Conn, fork))
    FAIL(htonl(AFPERR_PARAM) != FPByteLock_ext(Conn, fork, 0, 0 /* set */, 0, 100))
fin:
    FPDelete(Conn, vol, DIRDID_ROOT, name);
}

/* ----------- */
/* FIXME: broken since at least 3.1.12 */
STATIC void test66()
{
    char *name = "t66 FPByteLock_ext DF";
    ENTER_TEST

    if (Conn->afp_version < 30) {
        test_skipped(T_AFP3);
        goto test_exit;
    }

    test_bytelock_ext(VolID, name, OPENFORK_DATA);
test_exit:
    exit_test("FPByteRangeLockExt:test66: FPByteLock Data Fork");
}

/* ----------- */
/* FIXME: broken since at least 3.1.12 - could not locate fork */
STATIC void test67()
{
    char *name = "t67 FPByteLock_ext RF";
    ENTER_TEST

    if (Conn->afp_version < 30) {
        test_skipped(T_AFP3);
        goto test_exit;
    }

    test_bytelock_ext(VolID, name, OPENFORK_RSCS);
test_exit:
    exit_test("FPByteRangeLockExt:test67: FPByteLock Resource Fork");
}


/* -------------------------- */
STATIC void test195()
{
    char *name = "test195 illegal fork";
    DSI *dsi;
    dsi = &Conn->dsi;
    ENTER_TEST

    if (Conn->afp_version < 30) {
        test_skipped(T_AFP3);
        goto test_exit;
    }

    illegal_fork(dsi, AFP_BYTELOCK_EXT, name);
test_exit:
    exit_test("FPByteRangeLockExt:test195: illegal fork");
}

/* ----------- */
void FPByteRangeLockExt_test()
{
    ENTER_TESTSET
#if 0
    test66();
    test67();
#endif
    test195();
}
