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

/* ------------------------- */
STATIC void test82()
{
    int  dir;
    char *name = "t82 test dir";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = (1 << DIRPBIT_CDATE) | (1 << DIRPBIT_BDATE) |
                      (1 << DIRPBIT_MDATE)
                      | (1 << DIRPBIT_ACCESS) | (1 << DIRPBIT_FINFO) | (1 << DIRPBIT_UID) |
                      (1 << DIRPBIT_GID) ;
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

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

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, name, 0, bitmap)) {
        test_failed();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
    filedir.access[0] = 0;

    if (FPSetDirParms(Conn, vol, DIRDID_ROOT, name, bitmap, &filedir)) {
        test_failed();
        goto fin;
    }

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, "", 0, bitmap)) {
        test_failed();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
    filedir.access[0] = 0;

    if (FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir)) {
        test_failed();
        goto fin;
    }

fin:
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPSetDirParms:test82: test set dir parameters");
}

/* ------------------------- */
STATIC void test84()
{
    int  dir;
    char *name = "t84 no delete dir";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = (1 << DIRPBIT_ATTR) | (1 << DIRPBIT_FINFO) |
                      (1 << DIRPBIT_CDATE) |
                      (1 << DIRPBIT_BDATE) | (1 << DIRPBIT_MDATE) | (1 << DIRPBIT_UID) |
                      (1 << DIRPBIT_GID);
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

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

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, name, 0, bitmap)) {
        test_failed();
    } else {
        filedir.isdir = 1;
        afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
        filedir.attr = ATTRBIT_NODELETE | ATTRBIT_SETCLR ;
        FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, name, bitmap, &filedir))

        if (ntohl(AFPERR_OLOCK) != FPDelete(Conn, vol, DIRDID_ROOT, name)) {
            test_failed();
            goto test_exit;
        }

        filedir.attr = ATTRBIT_NODELETE;
        FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, name, bitmap, &filedir))
    }

    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPSetDirParms:test84: test dir set no delete attribute");
}

/* ------------------------- */
STATIC void test88()
{
    int  dir = 0;
    char *name = "t88 error setdirparams";
    char *name1 = "t88 error setdirparams file";
    char *name2 = "t88 error enoent file";
    char *ndir = "t88 no access";
    char *rodir = "t88 read only access";
    int  ofs =  3 * sizeof(uint16_t);
    int pdir = 0;
    int rdir = 0;
    struct afp_filedir_parms filedir;
    uint16_t bitmap = DIRPBIT_ATTR | (1 << DIRPBIT_FINFO) | (1 << DIRPBIT_CDATE) |
                      (1 << DIRPBIT_BDATE) | (1 << DIRPBIT_MDATE) | (1 << DIRPBIT_UID) |
                      (1 << DIRPBIT_GID) | (1 << DIRPBIT_ACCESS);
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    unsigned int ret;
    ENTER_TEST

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

    if (!(pdir = no_access_folder(vol, DIRDID_ROOT, ndir))) {
        goto test_exit;
    }

    if (!(rdir = read_only_folder(vol, DIRDID_ROOT, rodir))) {
        goto fin;
    }

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, ndir, 0,
                           (1 <<  DIRPBIT_LNAME) | (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) |
                           (1 << DIRPBIT_ACCESS))) {
        test_failed();
        goto fin;
    }

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, name))) {
        test_failed();
        goto fin;
    }

    if (FPCreateFile(Conn, vol, 0, dir, name1)) {
        test_failed();
        goto fin;
    }

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, name, 0, bitmap)) {
        test_failed();
    } else {
        filedir.isdir = 1;
        afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
        filedir.access[0] = 0;
        bitmap = (1 << DIRPBIT_ATTR);
        filedir.attr = ATTRBIT_INVISIBLE | ATTRBIT_SETCLR ;
        ret = FPSetDirParms(Conn, vol, DIRDID_ROOT, rodir, bitmap, &filedir);

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

        bitmap = (1 << DIRPBIT_CDATE) | (1 << DIRPBIT_BDATE) | (1 << DIRPBIT_MDATE);
        ret = FPSetDirParms(Conn, vol, DIRDID_ROOT, rodir, bitmap, &filedir);

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

        bitmap = (1 << DIRPBIT_UID) | (1 << DIRPBIT_GID) | (1 << DIRPBIT_ACCESS);
        FAIL(ntohl(AFPERR_ACCESS) != FPSetDirParms(Conn, vol, DIRDID_ROOT, ndir, bitmap,
                &filedir))
        FAIL(ntohl(AFPERR_BADTYPE) != FPSetDirParms(Conn, vol, dir, name1, bitmap,
                &filedir))
        FAIL(ntohl(AFPERR_NOOBJ) != FPSetDirParms(Conn, vol, dir, name2, bitmap,
                &filedir))
    }

fin:
    delete_folder(vol, DIRDID_ROOT, ndir);

    if (rdir) {
        delete_folder(vol, DIRDID_ROOT, rodir);
    }

    FAIL(dir && FPDelete(Conn, vol, dir, name1))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPSetDirParms:test88: test error setdirparam");
}

/* ------------------------- */
STATIC void test107()
{
    int  dir;
    int  pdir;
    char *name = "t107 test dir";
    char *ndir = "t107 no access";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = (1 << DIRPBIT_CDATE) | (1 << DIRPBIT_BDATE) |
                      (1 << DIRPBIT_MDATE)
                      | (1 << DIRPBIT_ACCESS) | (1 << DIRPBIT_FINFO) | (1 << DIRPBIT_UID) |
                      (1 << DIRPBIT_GID) ;
    uint16_t bitmap2 = (1 << DIRPBIT_ACCESS) | (1 << DIRPBIT_UID) |
                       (1 << DIRPBIT_GID) ;
    int uid;
    int ret;
    uint16_t vol = VolID;
    uint16_t vol2;
    const DSI *dsi2;
    ENTER_TEST

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

    if (!(pdir = no_access_folder(vol, DIRDID_ROOT, ndir))) {
        goto test_exit;
    }

    dsi2 = &Conn2->dsi;
    vol2  = FPOpenVol(Conn2, Vol);

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

    if (!(dir = FPCreateDir(Conn2, vol2, DIRDID_ROOT, name))) {
        test_nottested();
        goto fin;
    }

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

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi2->data + ofs, 0, bitmap);
    filedir.access[0] = 0;
    uid = filedir.uid;

    if (FPGetFileDirParams(Conn2, vol2,  DIRDID_ROOT, name, 0, bitmap)) {
        test_failed();
    } else {
        filedir.isdir = 1;
        afp_filedir_unpack(&filedir, dsi2->data + ofs, 0, bitmap);
        filedir.access[0] = 0;
        filedir.uid = uid;
        /* change owner */
        FAIL(FPSetDirParms(Conn2, vol2, DIRDID_ROOT, name, bitmap2, &filedir))
    }

    if (FPGetFileDirParams(Conn2, vol2,  DIRDID_ROOT, ndir, 0, bitmap)) {
        test_failed();
    } else {
        filedir.isdir = 1;
        afp_filedir_unpack(&filedir, dsi2->data + ofs, 0, bitmap);
        filedir.access[0] = 0;
        filedir.uid = uid;
        FAIL(FPSetDirParms(Conn2, vol2, DIRDID_ROOT, ndir, bitmap2, &filedir))
    }

    if (FPGetFileDirParams(Conn2, vol2,  DIRDID_ROOT, "", 0, bitmap)) {
        test_failed();
    } else {
        filedir.isdir = 1;
        afp_filedir_unpack(&filedir, dsi2->data + ofs, 0, bitmap);
        filedir.access[0] = 0;
        filedir.uid = uid;
        ret = FPSetDirParms(Conn2, vol2, DIRDID_ROOT, "", bitmap2, &filedir);

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

        filedir.access[0] = 0;
        filedir.access[1] = 7;
        filedir.access[2] = 7;
        filedir.access[3] = 7;
        ret = FPSetDirParms(Conn2, vol2, DIRDID_ROOT, "", bitmap2, &filedir);

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

    FAIL(FPDelete(Conn2, vol2,  DIRDID_ROOT, name))
    FAIL(FPCloseVol(Conn2, vol2))
fin:
    delete_folder(vol, DIRDID_ROOT, ndir);
test_exit:
    exit_test("FPSetDirParms:test107: test dir");
}


/* ------------------------- */
STATIC void test189()
{
    int  dir;
    char *name = "t189 error setdirparams";
    char *name1 = "t189 error setdirparams file";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = (1 << DIRPBIT_FINFO) | (1 << DIRPBIT_CDATE) |
                      (1 << DIRPBIT_BDATE) | (1 << DIRPBIT_MDATE) | (1 << DIRPBIT_UID) |
                      (1 << DIRPBIT_GID) | (1 << DIRPBIT_ACCESS);
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

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

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

    if (FPCreateFile(Conn, vol, 0, dir, name1)) {
        test_nottested();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
    filedir.access[0] = 0;
    FAIL(ntohl(AFPERR_BADTYPE) != FPSetDirParms(Conn, vol, dir, name1, bitmap,
            &filedir))
    FAIL(FPDelete(Conn, vol, dir, name1))
fin:
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPSetDirParms:test189: test error setdirparam");
}

/* ------------------------- */
STATIC void test193()
{
    int  dir;
    char *name = "t193 no delete dir";
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = (1 << DIRPBIT_ACCESS);
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    int ret;
    ENTER_TEST

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

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, name, 0, bitmap)) {
        test_failed();
    } else {
        filedir.isdir = 1;
        afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
        ret = FPSetDirParms(Conn, vol, DIRDID_ROOT, name, bitmap, &filedir);

        if (not_valid(ret, /* MAC */AFPERR_PARAM, 0)) {
            test_failed();
        }

        filedir.access[0] = 0;
        FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, name, bitmap, &filedir))
    }

    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPSetDirParms:test193: user permission set");
}

/* ------------------------- */
STATIC void test351()
{
    int  dir = 0;
    char *ndir = "t351 dir";
    char *name = "t351 file";
    uint16_t vol = VolID;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = 0;
    uint8_t old_access[4];
    int ret;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, ndir))) {
        test_nottested();
        goto test_exit;
    }

    bitmap = (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) | (1 << DIRPBIT_ACCESS);

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, "", 0, bitmap)) {
        test_failed();
        goto fin;
    }

    memset(&filedir, 0, sizeof(filedir));
    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs,  0, bitmap);
    bitmap = (1 << DIRPBIT_ACCESS);
    filedir.access[0] = 0;
    memcpy(old_access, filedir.access, sizeof(old_access));
    filedir.access[1] = filedir.access[2] = filedir.access[3] = 0;
    ret = FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir);

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

    if (!ret) {
        memcpy(filedir.access, old_access, sizeof(old_access));
        FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir))
    }

    filedir.access[3] = 3; /* only owner */
    FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir))

    if (!FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
        FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
    }

    memcpy(filedir.access, old_access, sizeof(old_access));
    FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir))

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
    }

fin:
    FAIL(FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPSetDirParms:test351: change root folder unix perm");
}

/* ------------------------- */
STATIC void test352()
{
    int  dir = 0;
    char *name = "t352 file";
    char *ndir = "t352 dir";
    uint16_t vol = VolID;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = 0;
    uint8_t old_access[4];
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, ndir))) {
        test_nottested();
        goto test_exit;
    }

    bitmap = (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) | (1 << DIRPBIT_ACCESS);

    if (FPGetFileDirParams(Conn, vol, dir, "", 0, bitmap)) {
        test_failed();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
    bitmap = (1 << DIRPBIT_ACCESS);
    filedir.unix_priv = 0;
    filedir.access[0] = 0;
    memcpy(old_access, filedir.access, sizeof(old_access));
    filedir.access[1] = filedir.access[2] = filedir.access[3] = 0;
    FAIL(FPSetDirParms(Conn, vol, dir, "", bitmap, &filedir))

    if (!FPCreateFile(Conn, vol, 0, dir, name)) {
        test_failed();
        FAIL(FPDelete(Conn, vol, dir, name))
    }

    /* double check with didn't screw the parent !*/
    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
    }

    memcpy(filedir.access, old_access, sizeof(old_access));
    FAIL(FPSetDirParms(Conn, vol, dir, "", bitmap, &filedir))

    if (FPCreateFile(Conn, vol, 0, dir, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, dir, name))
    }

fin:
    FAIL(FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPSetDirParms:test352: Change Mac perm to no perm in root folder");
}

/* ------------------------- */
STATIC void test353()
{
    int  dir = 0;
    char *name = "t353 file";
    char *ndir = "t353 dir";
    uint16_t vol = VolID;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = 0;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (get_vol_attrib(vol) & VOLPBIT_ATTR_UNIXPRIV) {
        test_skipped(T_NO_UNIX_PREV);
        goto test_exit;
    }

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, ndir))) {
        test_nottested();
        goto test_exit;
    }

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

    bitmap = (1 << DIRPBIT_PDINFO) | (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) |
             (1 << DIRPBIT_UNIXPR);

    if (FPGetFileDirParams(Conn, vol, dir, "", 0, bitmap)) {
        test_failed();
        goto fin1;
    }

    bitmap = (1 << DIRPBIT_UNIXPR);
    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
    bitmap = (1 << DIRPBIT_UNIXPR);
    filedir.unix_priv = 1;
    filedir.access[0] = 0;
    filedir.access[1] = filedir.access[2] = filedir.access[3] = 0;

    if (htonl(AFPERR_BITMAP) != FPSetDirParms(Conn, vol, dir, "", bitmap,
            &filedir)) {
        test_failed();
        filedir.unix_priv = S_IRUSR | S_IWUSR;
        FAIL(FPSetDirParms(Conn, vol, dir, "", bitmap, &filedir))
    }

    bitmap = (1 <<  FILPBIT_PDINFO) | (1 << FILPBIT_PDID) | (1 << FILPBIT_FNUM) |
             (1 << DIRPBIT_UNIXPR);

    if (/* htonl(AFPERR_BITMAP) != */ FPGetFileDirParams(Conn, vol, dir, name,
                                      bitmap, 0)) {
        test_failed();
        goto fin1;
    }

    bitmap = (1 <<  FILPBIT_PDINFO) | (1 << FILPBIT_PDID) | (1 << FILPBIT_FNUM);

    if (FPGetFileDirParams(Conn, vol, dir, name, bitmap, 0)) {
        test_failed();
        goto fin1;
    }

    filedir.isdir = 0;
    afp_filedir_unpack(&filedir, dsi->data + ofs, bitmap, 0);
    bitmap = (1 << DIRPBIT_UNIXPR);
    filedir.unix_priv = 0;
    filedir.access[0] = 0;
    filedir.access[1] = filedir.access[2] = filedir.access[3] = 0;

    if (htonl(AFPERR_BITMAP) != FPSetFilDirParam(Conn, vol, dir, name, bitmap,
            &filedir)) {
        test_failed();
        filedir.unix_priv = S_IRUSR | S_IWUSR;
        FAIL(FPSetFilDirParam(Conn, vol, dir, name, bitmap, &filedir))
    }

fin1:
    FAIL(FPDelete(Conn, vol, dir, name))
fin:
    FAIL(FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPSetDirParms:test353: no unix access privilege");
}

/* ------------------------- */
STATIC void test354()
{
    int  dir = 0;
    char *ndir = "t354 dir";
    char *name = "t354 file";
    uint16_t vol = VolID;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = 0;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (!(get_vol_attrib(vol) & VOLPBIT_ATTR_UNIXPRIV)) {
        test_skipped(T_UNIX_PREV);
        goto test_exit;
    }

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, ndir))) {
        test_nottested();
        goto test_exit;
    }

    bitmap = (1 << DIRPBIT_PDINFO) | (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) |
             (1 << DIRPBIT_UNIXPR);

    if (FPGetFileDirParams(Conn, vol, dir, "", 0, bitmap)) {
        test_failed();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
    bitmap = (1 << DIRPBIT_UNIXPR);
    filedir.unix_priv = 0;
    filedir.access[0] = 0;
    filedir.access[1] = filedir.access[2] = filedir.access[3] = 0;
    FAIL(FPSetDirParms(Conn, vol, dir, "", bitmap, &filedir))

    if (!FPCreateFile(Conn, vol, 0, dir, name)) {
        test_failed();
        FAIL(FPDelete(Conn, vol, dir, name))
    }

    /* double check with didn't screw the parent !*/
    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
    }

    filedir.unix_priv = S_IRUSR | S_IWUSR | S_IXUSR ;
    FAIL(FPSetDirParms(Conn, vol, dir, "", bitmap, &filedir))

    if (FPCreateFile(Conn, vol, 0, dir, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, dir, name))
    }

fin:
    FAIL(FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPSetDirParms:test354: change a folder perm in root folder");
}

/* ------------------------- */
STATIC void test355()
{
    int  dir = 0;
    int  dir1 = 0;
    char *ndir = "t355 dir";
    char *ndir1 = "t355 subdir";
    char *name = "t355 file";
    uint16_t vol = VolID;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = 0;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (!(get_vol_attrib(vol) & VOLPBIT_ATTR_UNIXPRIV)) {
        test_skipped(T_UNIX_PREV);
        goto test_exit;
    }

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, ndir))) {
        test_nottested();
        goto test_exit;
    }

    if (!(dir1 = FPCreateDir(Conn, vol, dir, ndir1))) {
        test_nottested();
        goto fin;
    }

    bitmap = (1 << DIRPBIT_PDINFO) | (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) |
             (1 << DIRPBIT_UNIXPR);

    if (FPGetFileDirParams(Conn, vol, dir1, "", 0, bitmap)) {
        test_failed();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs,  0, bitmap);
    bitmap = (1 << DIRPBIT_UNIXPR);
    filedir.unix_priv = 0;
    filedir.access[0] = 0;
    filedir.access[1] = filedir.access[2] = filedir.access[3] = 0;
    FAIL(FPSetDirParms(Conn, vol, dir1, "", bitmap, &filedir))

    if (!FPCreateFile(Conn, vol, 0, dir1, name)) {
        test_failed();
        FAIL(FPDelete(Conn, vol, dir1, name))
    }

    /* double check with didn't screw the parent !*/
    if (FPCreateFile(Conn, vol, 0, dir, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, dir, name))
    }

    filedir.unix_priv = S_IRUSR | S_IWUSR | S_IXUSR ;
    FAIL(FPSetDirParms(Conn, vol, dir1, "", bitmap, &filedir))

    if (FPCreateFile(Conn, vol, 0, dir1, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, dir1, name))
    }

fin:
    FAIL(dir1 && FPDelete(Conn, vol, dir1, ""))
    FAIL(FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPSetDirParms:test355: change a folder perm in a folder");
}

/* ------------------------- */
STATIC void test356()
{
    int  dir = 0;
    char *ndir = "t356 dir";
    char *name = "t356 file";
    uint16_t vol = VolID;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = 0;
    int old_unixpriv;
    int ret;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (!(get_vol_attrib(vol) & VOLPBIT_ATTR_UNIXPRIV)) {
        test_skipped(T_UNIX_PREV);
        goto test_exit;
    }

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, ndir))) {
        test_nottested();
        goto test_exit;
    }

    bitmap = (1 << DIRPBIT_PDINFO) | (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) |
             (1 << DIRPBIT_UNIXPR);

    if (FPGetFileDirParams(Conn, vol, DIRDID_ROOT, "", 0, bitmap)) {
        test_failed();
        goto fin;
    }

    memset(&filedir, 0, sizeof(filedir));
    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs,  0, bitmap);
    bitmap = (1 << DIRPBIT_UNIXPR);
    old_unixpriv = filedir.unix_priv;
    filedir.unix_priv = 0;
    filedir.access[0] = 0;
    filedir.access[1] = filedir.access[2] = filedir.access[3] = 0;
    ret = FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir);

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

    if (!ret) {
        filedir.unix_priv = old_unixpriv;
        FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir))
    }

    filedir.unix_priv = S_IRUSR | S_IXUSR ;
    FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir))

    if (!FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
        FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
    }

    filedir.unix_priv = old_unixpriv;
    FAIL(FPSetDirParms(Conn, vol, DIRDID_ROOT, "", bitmap, &filedir))

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
    } else {
        FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
    }

fin:
    FAIL(FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPSetDirParms:test356: change root folder unix perm");
}

/* ---------------------- */
static gid_t   *groups;
#define GROUPS_SIZE sizeof(gid_t)
static int     ngroups;

static int init_groups(void)
{
    if ((ngroups = getgroups(0, NULL)) < 0) {
        return 0;
    }

    if (ngroups < 2) {
        /* we need at least 2 groups for testing */
        return 0;
    }

    if (NULL == (groups = calloc(ngroups, GROUPS_SIZE))) {
        return 0;
    }

    if ((ngroups = getgroups(ngroups, groups)) < 0) {
        return 0;
    }

    return ngroups;
}

/* -----------------
 * only work if client and server share the same numeric ids
*/
static  int check_group(gid_t group)
{
    int i, j;

    for (i = 0; i < ngroups; i++) {
        if (groups[i] == group) {
            for (j = 0; j < ngroups; j++) {
                if (groups[j] != group) {
                    /* find a different group */
                    return groups[j];
                }
            }

            return 0;
        }
    }

    return 0;
}


/* ------------------------- */
STATIC void test405()
{
    int  dir = 0;
    char *ndir = "t405 dir";
    uint16_t vol = VolID;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t bitmap = 0;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (!(get_vol_attrib(vol) & VOLPBIT_ATTR_UNIXPRIV)) {
        test_skipped(T_UNIX_PREV);
        goto test_exit;
    }

    if (!init_groups()) {
        test_skipped(T_UNIX_GROUP);
        goto test_exit;
    }

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, ndir))) {
        test_nottested();
        goto test_exit;
    }

    bitmap = (1 << DIRPBIT_PDINFO) | (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID) |
             (1 << DIRPBIT_UNIXPR);

    if (FPGetFileDirParams(Conn, vol, dir, "", 0, bitmap)) {
        test_failed();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);

    if (!(filedir.gid = check_group(filedir.gid))) {
        test_skipped(T_UNIX_GROUP);
        FPDelete(Conn, vol, dir, "");
        goto test_exit;
    }

    bitmap = (1 << DIRPBIT_UNIXPR);
    FAIL(FPSetDirParms(Conn, vol, dir, "", bitmap, &filedir))
fin:
    FAIL(FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPSetDirParms:test405: change a folder group owner in the root folder");
}

/* ----------- */
void FPSetDirParms_test()
{
    ENTER_TESTSET
    test82();
    test84();
    test88();
    test107();
    test189();
    test193();
    test351();
    test352();
    test353();
    test354();
    test355();
    test356();
    test405();
}
