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

#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

static char temp[MAXPATHLEN];

/* ------------------------- */
static void test_bytelock(uint16_t vol2, char *name, int type)
{
    int fork;
    int fork1;
    uint16_t bitmap = 0;
    int len = (type == OPENFORK_RSCS) ? (1 << FILPBIT_RFLEN) : (1 << FILPBIT_DFLEN);
    struct flock lock;
    int fd;
    int ret;
    uint16_t vol = VolID;

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
        return;
    }

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

    if (!fork) {
        test_failed();
        FPDelete(Conn, vol, DIRDID_ROOT, name);
        return;
    }

    if (!Quiet && FPSetForkParam(Conn, fork, len, 50)) {
        fprintf(stdout, "\tFAILED\n");
    }

    if (!Quiet && FPByteLock(Conn, fork, 0, 0, 0, 100)) {
        fprintf(stdout, "\tFAILED\n");
    }

    if (!Quiet && FPRead(Conn, fork, 0, 40, Data)) {
        fprintf(stdout, "\tFAILED\n");
    }

    if (!Quiet && FPWrite(Conn, fork, 10, 40, Data, 0)) {
        fprintf(stdout, "\tFAILED\n");
    }

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

    if (fork1) {
        test_failed();
        FPCloseFork(Conn, fork);
    }

    strcpy(temp, Path);
    strcat(temp, (type == OPENFORK_RSCS
                  && adouble == AD_V2) ? "/.AppleDouble/" : "/");
    strcat(temp, name);

    if (!Quiet) {
        fprintf(stdout, " \n---------------------\n");
        fprintf(stdout, "open(\"%s\", O_RDWR)\n", temp);
    }

    fd = open(temp, O_RDWR, 0);

    if (fd >= 0) {
        if (adouble == AD_V2) {
            lock.l_start = 0;
            lock.l_len = 1024;
        } else {
            lock.l_start = AD_FILELOCK_BASE;
            lock.l_len = 8;
        }

        lock.l_type = F_WRLCK;
        lock.l_whence = SEEK_SET;

        if ((ret = fcntl(fd, F_SETLK, &lock)) >= 0 || (errno != EACCES
                && errno != EAGAIN)) {
            if (!ret >= 0) {
                errno = 0;
            }

            if (!Quiet) {
                perror("fcntl ");
                fprintf(stdout, "\tFAILED\n");
            }
        }

        fcntl(fd, F_UNLCK, &lock);
        close(fd);
    } else if (!Quiet) {
        perror("open ");
        fprintf(stdout, "\tFAILED \n");
    }

    fork1 = FPOpenFork(Conn2, vol2, type, bitmap, DIRDID_ROOT, name,
                       OPENACC_WR | OPENACC_RD);

    if (fork1) {
        if (!Quiet) {
            fprintf(stdout, "\tFAILED\n");
        }

        FPCloseFork(Conn2, fork1);
    }

    FPCloseFork(Conn, fork);
    fork1 = FPOpenFork(Conn2, vol2, type, bitmap, DIRDID_ROOT, name,
                       OPENACC_WR | OPENACC_RD);

    if (!fork1) {
        test_failed();

        if (!Quiet) {
            fprintf(stdout, "\tFAILED\n");
        }
    } else {
        FAIL(FPCloseFork(Conn2, fork1))
    }

    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
}

/* -------------------- */
void test117()
{
    char *name = "t117 exclusive open DF";
    uint16_t vol2;
    ENTER_TEST

    if (Path[0] == '\0') {
        test_skipped(T_PATH);
        goto test_exit;
    }

    if (!Conn2) {
        test_skipped(T_CONN2);
        goto test_exit;
    }

    vol2  = FPOpenVol(Conn2, Vol);

    if (vol2 == 0xffff) {
        test_nottested();
        goto test_exit;
    }

#if 0
    test_bytelock(vol2, name, OPENFORK_DATA);
#endif
    name = "t117 exclusive open RF";
    test_bytelock(vol2, name, OPENFORK_RSCS);
    FPCloseVol(Conn2, vol2);
test_exit:
    exit_test("FPByteRangeLock:test117: test open excl mode");
}

/* ----------- */
void T2FPByteRangeLock_test()
{
    ENTER_TESTSET
    test117();
}
