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

/* ------------------------ */
static int afp_symlink(char *oldpath, char *newpath)
{
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap;
    uint16_t vol = VolID;
    const DSI *dsi;
    int fork = 0;
    dsi = &Conn->dsi;

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, newpath)) {
        return -1;
    }

    fork = FPOpenFork(Conn, vol, OPENFORK_DATA, 0, DIRDID_ROOT, newpath,
                      OPENACC_WR | OPENACC_RD);

    if (!fork) {
        return -1;
    }

    if (FPWrite(Conn, fork, 0, (int)strlen(oldpath), oldpath, 0)) {
        return -1;
    }

    if (FPCloseFork(Conn, fork)) {
        return -1;
    }

    fork = 0;
    bitmap = (1 << DIRPBIT_ATTR) | (1 << FILPBIT_FINFO) |
             (1 << DIRPBIT_CDATE) | (1 << DIRPBIT_MDATE) |
             (1 << DIRPBIT_LNAME) | (1 << DIRPBIT_PDID) | (1 << FILPBIT_FNUM);

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, newpath, bitmap, 0)) {
        return -1;
    }

    filedir.isdir = 0;
    afp_filedir_unpack(&filedir, dsi->data + ofs, bitmap, 0);
    memcpy(filedir.finder_info, "slnkrhap", 8);
    bitmap = (1 << FILPBIT_FINFO);

    if (FPSetFileParams(Conn, vol, DIRDID_ROOT, newpath, bitmap, &filedir)) {
        return -1;
    }

    return 0;
}

/* ------------------------- */
STATIC void test89()
{
    int  dir;
    char *file = "t89 test error setfilparam";
    char *name = "t89 error setfilparams dir";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = (1 << FILPBIT_FINFO) | (1 << FILPBIT_CDATE) |
                      (1 << FILPBIT_BDATE) | (1 << FILPBIT_MDATE);
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    unsigned ret;
    ENTER_TEST

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

    if (!(dir = folder_with_ro_adouble(vol, DIRDID_ROOT, name, file))) {
        test_nottested();
        goto test_exit;
    }

    if (FPGetFileDirParams(Conn, vol, dir, file, bitmap, 0)) {
        test_failed();
    } else {
        filedir.isdir = 0;
        afp_filedir_unpack(&filedir, dsi->data + ofs, bitmap, 0);
        ret = FPSetFileParams(Conn, vol, dir, file, bitmap, &filedir);

        if (not_valid(ret, 0, AFPERR_ACCESS)) {
            test_failed();
        }
    }

    bitmap = (1 << FILPBIT_MDATE);

    if (FPGetFileDirParams(Conn, vol, dir, file, bitmap, 0)) {
        test_failed();
    } else {
        filedir.isdir = 0;
        afp_filedir_unpack(&filedir, dsi->data + ofs, bitmap, 0);
        FAIL(FPSetFileParams(Conn, vol, dir, file, bitmap, &filedir))
    }

    delete_ro_adouble(vol, dir, file);
test_exit:
    exit_test("FPSetFileParms:test89: test set file setfilparam");
}

/* ------------------------- */
STATIC void test120()
{
    char *name = "t120 test file setfilparam";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = (1 << FILPBIT_ATTR) | (1 << FILPBIT_FINFO) |
                      (1 << FILPBIT_CDATE) |
                      (1 << FILPBIT_BDATE) | (1 << FILPBIT_MDATE);
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

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

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

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, name, bitmap, 0)) {
        test_failed();
    } else {
        filedir.isdir = 0;
        afp_filedir_unpack(&filedir, dsi->data + ofs, bitmap, 0);
        delete_unix_md(Path, "", name);
        FAIL(FPSetFileParams(Conn, vol, DIRDID_ROOT, name, bitmap, &filedir))
    }

    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPSetFileParms:test120: test set file setfilparam (create .AppleDouble)");
}

/* ------------------------- */
STATIC void test426()
{
    char *name = "t426 Symlink";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap;
    uint16_t vol = VolID;
    DSI *dsi;
    int fork = 0;
    unsigned int ret;
    char temp[MAXPATHLEN];
    struct stat st;
    dsi = &Conn->dsi;
    ENTER_TEST

    /* FIXME: This test hangs with AFP2.x (3.1.12 - 4.0.3) */
    if (Conn->afp_version < 30) {
        test_skipped(T_AFP3);
        return;
    }

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

    if (afp_symlink("t426 dest", name)) {
        test_nottested();
        goto test_exit;
    }

    /* Check if volume uses option 'followsymlinks' */
    sprintf(temp, "%s/%s", Path, name);

    if (lstat(temp, &st)) {
        if (!Quiet) {
            fprintf(stdout, "\tFAILED stat( %s ) %s\n", temp, strerror(errno));
        }

        test_failed();
    }

    if (!S_ISLNK(st.st_mode)) {
        test_skipped(T_NOSYML);
        goto test_exit;
    }

    fork = FPOpenFork(Conn, vol, OPENFORK_DATA, 0, DIRDID_ROOT, name,
                      OPENACC_WR | OPENACC_RD);

    if (!fork) {
        test_failed();
    } else {
        char *ln2 = "t426 dest 2";
        ret = FPWrite_ext(Conn, fork, 0, (off_t)strlen(ln2), ln2, 0);

        if (not_valid_bitmap(ret, BITERR_ACCESS | BITERR_MISC, AFPERR_MISC)) {
            test_failed();
        }

        FPCloseFork(Conn, fork);
    }

    fork = FPOpenFork(Conn, vol, OPENFORK_DATA, 0, DIRDID_ROOT, name, OPENACC_RD);

    if (!fork) {
        /* Trying to open the linked file? */
        test_failed();
    }

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

    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPSetFileParms:test426: Create a dangling symlink");
}

/* ----------- */
void T2FPSetFileParms_test()
{
    ENTER_TESTSET
    test89();
    test120();
    test426();
}
