tests: add ncpfs directory quota smoke
All checks were successful
Source release / source-package (push) Successful in 1m7s
All checks were successful
Source release / source-package (push) Successful in 1m7s
This commit is contained in:
2
AI.md
2
AI.md
@@ -1,4 +1,6 @@
|
||||
|
||||
Patch 0353 status: added live NCPFS directory-quota smoke for 3.x endpoints. `nwfs_ncpfs_dirquota` now drives decimal `22/36`/wire `0x24` and decimal `22/35`/wire `0x23` directly through libncp `NCPC_SFN`, with readback/expect modes. `nwfs_ncpfs_dirquota_smoke.sh` sets a limit, reads it back over NCP, verifies `netware.metadata`, clears it, and verifies that `22/35` reports no entries.
|
||||
|
||||
Patch 0351 status: started closing the MARS-NWE 3.x directory-quota block before namespace work. Added libnwfs `dirquota.c/h`, CTest `nwfs_dirquota_test`, active NCP `22/35`/wire `0x23` get and `22/36`/wire `0x24` set backed by `netware.metadata.nwm_quota_limit`, and fixed `22/40`/wire `0x28` Sequence parsing to Lo-Hi. Code comments name both decimal NCP numbers and wire hex bytes. Remaining directory-quota work is enforcement/adjustment on file growth/create/delete/rename and later `87/39` behind the 4.x line.
|
||||
# AI working notes for mars-nwe
|
||||
|
||||
|
||||
12
REDESIGN.md
12
REDESIGN.md
@@ -3410,3 +3410,15 @@ The first NetWare-3.x directory-quota pass is active as of patch 0351. Document
|
||||
`src/nwfs/quota/dirquota.c` is the libnwfs home for portable directory-quota math and NSS/OES-compatible `netware.metadata.nwm_quota_limit` conversion. The live NCP parser stays in `src/nwconn.c`. `22/35` returns no entries for unrestricted directories and one current-directory entry for a finite restriction. `22/36` stores or clears the directory restriction in `netware.metadata`. `22/40` now reads its sequence field as documented Lo-Hi and continues to use the existing MARS DOS scan reply shape until AFP/MAC_RF resource fork data exists.
|
||||
|
||||
This closes the first 3.x directory-quota endpoint gap without pulling in the full NSS `dirQuotas.c` runtime/cache. Deeper NSS-style parent-min restriction selection, used-space adjustment hooks on create/delete/rename/write, and namespace-aware `87/39` remain follow-up work.
|
||||
|
||||
|
||||
### NCPFS directory-quota smoke
|
||||
|
||||
The directory-quota implementation now has two test layers. The CTest helper
|
||||
`nwfs_dirquota_test` validates the libnwfs arithmetic and metadata conversion.
|
||||
The live smoke `nwfs_ncpfs_dirquota_smoke.sh` validates the NetWare 3.x NCP
|
||||
path: it uses libncp `NCPC_SFN(22, 36)` to send decimal `22/36` (wire/code
|
||||
`0x24`) and `NCPC_SFN(22, 35)` for decimal `22/35` (wire/code `0x23`). The
|
||||
smoke intentionally verifies both the NCP readback and the host-side
|
||||
`netware.metadata` result, so parser/wire mistakes and xattr-storage mistakes
|
||||
are caught independently.
|
||||
|
||||
13
TODO.md
13
TODO.md
@@ -2507,3 +2507,16 @@ Do not merge these back together; a later BSD backend should use its own
|
||||
- Keep Linuxquota, NWQUOTA, and future BSD quota backends in separate files with
|
||||
separate public prefixes: `nwfs_lnxquota_*`, `nwfs_nwquota_*`, and future
|
||||
`nwfs_bsdquota_*`.
|
||||
|
||||
|
||||
### Directory quota live smoke
|
||||
|
||||
- Added/keep `tests/nwfs/nwfs_ncpfs_dirquota_smoke.sh` for the 3.x directory
|
||||
quota endpoints. The helper must name the documented decimal calls and the
|
||||
code/wire hex values together:
|
||||
- decimal `22/36`, wire/code `0x24`: set directory disk-space restriction
|
||||
- decimal `22/35`, wire/code `0x23`: get directory disk-space restriction
|
||||
- The smoke should stay a live NCPFS test, not just a host xattr test: set over
|
||||
NCP, read over NCP, then verify `netware.metadata` on the host side.
|
||||
- `22/40` remains the next directory-quota smoke target once the scan reply
|
||||
is verified against the documented structure.
|
||||
|
||||
@@ -99,3 +99,14 @@ The first active implementation stores finite directory restrictions in
|
||||
`netware.metadata.nwm_quota_limit`. Screenshots from FILER, SYSCON, NWADMIN or
|
||||
reference NetWare servers that demonstrate directory quota behaviour belong
|
||||
under this `doc/quota/` tree.
|
||||
|
||||
|
||||
## Directory quota smoke
|
||||
|
||||
`tests/nwfs/nwfs_ncpfs_dirquota_smoke.sh` is the live smoke for the NetWare
|
||||
3.x directory disk-space restriction calls. It sets a limit with documented
|
||||
decimal `22/36` (wire/code `0x24`), reads it back with documented decimal
|
||||
`22/35` (wire/code `0x23`), verifies `netware.metadata`, clears the limit, and
|
||||
checks that `22/35` returns no entries again. Future screenshots from FILER,
|
||||
SYSCON, or NetWare reference systems for this behavior belong under
|
||||
`doc/quota/screenshots/`.
|
||||
|
||||
@@ -85,3 +85,23 @@ Tests must therefore not validate salvage payloads by opening
|
||||
`SYS:.recycle/...` or `SYS:.salvage/...` through normal NCP file calls. Use the
|
||||
salvage scan/recover/purge endpoints for repository state and verify payload
|
||||
content by reading the restored live file through NCP.
|
||||
|
||||
|
||||
## NCPFS directory-quota smoke
|
||||
|
||||
`tests/nwfs/nwfs_ncpfs_dirquota_smoke.sh` is the live smoke for the
|
||||
MARS-NWE 3.x directory quota endpoints. It uses the `nwfs_ncpfs_dirquota`
|
||||
helper to call the documented decimal NCPs `22/36` and `22/35` directly
|
||||
through libncp (`NCPC_SFN(22, 36)` and `NCPC_SFN(22, 35)`; wire/code bytes
|
||||
`0x24` and `0x23`). The smoke sets a finite directory limit, reads it back,
|
||||
checks `netware.metadata` with `nwfs_xattr_dump`, clears the limit, and
|
||||
verifies that `22/35` reports no entries again.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
./nwfs_ncpfs_dirquota_smoke.sh MARS SUPERVISOR secret \
|
||||
/var/mars_nwe/SYS /mnt/nw-sys NWFSTEST SYS
|
||||
```
|
||||
|
||||
Use `NWFS_NCPFS_DIR_QUOTA_4K=VALUE` to choose the tested limit.
|
||||
|
||||
@@ -63,12 +63,15 @@ configure_file(nwfs_ncpfs_novell_quota_reference.sh.in nwfs_ncpfs_novell_quota_r
|
||||
|
||||
configure_file(nwfs_ncpfs_userquota_fill_smoke.sh.in nwfs_ncpfs_userquota_fill_smoke.sh @ONLY)
|
||||
configure_file(nwfs_ncpfs_userquota_dual_smoke.sh.in nwfs_ncpfs_userquota_dual_smoke.sh @ONLY)
|
||||
configure_file(nwfs_ncpfs_dirquota_smoke.sh.in nwfs_ncpfs_dirquota_smoke.sh @ONLY)
|
||||
set(NWFS_NCPFS_DIRQUOTA_SMOKE "${CMAKE_CURRENT_BINARY_DIR}/nwfs_ncpfs_dirquota_smoke.sh")
|
||||
|
||||
foreach(NWFS_NCPFS_SMOKE_SCRIPT
|
||||
nwfs_ncpfs_metadata_smoke.sh
|
||||
nwfs_ncpfs_novell_quota_reference.sh
|
||||
nwfs_ncpfs_userquota_fill_smoke.sh
|
||||
nwfs_ncpfs_userquota_dual_smoke.sh)
|
||||
nwfs_ncpfs_userquota_dual_smoke.sh
|
||||
nwfs_ncpfs_dirquota_smoke.sh)
|
||||
file(CHMOD "${CMAKE_CURRENT_BINARY_DIR}/${NWFS_NCPFS_SMOKE_SCRIPT}"
|
||||
PERMISSIONS
|
||||
OWNER_READ OWNER_WRITE OWNER_EXECUTE
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Manual NCPFS smoke helper for NetWare directory space limits.
|
||||
* Manual NCPFS smoke helper for NetWare 3.x directory disk-space limits.
|
||||
*
|
||||
* This is intentionally small and is based on the ncpfs contrib/testing
|
||||
* dirlimit.c example by Petr Vandrovec. It mutates a directory through
|
||||
* libncp/NCPFS so the host-side test can verify the mars-nwe
|
||||
* netware.metadata directory-quota xattr afterwards.
|
||||
* The NCP documentation names these as decimal 22/35 and 22/36. libncp's
|
||||
* NCPC_SFN(22, 35/36) builds the same group/subfunction request that mars-nwe
|
||||
* dispatches as wire/code bytes 0x23 and 0x24 in src/nwconn.c.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -17,14 +17,108 @@
|
||||
#include <ncp/nwcalls.h>
|
||||
#include <ncp/nwnet.h>
|
||||
|
||||
#ifndef NCPC_SFN
|
||||
#define NCPC_SUBFUNCTION 0x10000U
|
||||
#define NCPC_SFN(fn, subfn) (NCPC_SUBFUNCTION | (((fn) & 0xffU) << 8) | ((subfn) & 0xffU))
|
||||
#endif
|
||||
|
||||
struct dirquota_entry {
|
||||
uint8_t level;
|
||||
uint32_t max4k;
|
||||
uint32_t current4k;
|
||||
};
|
||||
|
||||
static void usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-l LIMIT_4K] [-p VOLUME:PATH] NCPFS_MOUNTED_PATH\n"
|
||||
"Usage: %s [--set-limit-4k LIMIT] [--get] [--expect-limit-4k LIMIT|--expect-empty] [-p VOLUME:PATH] NCPFS_MOUNTED_PATH\n"
|
||||
" %s -l LIMIT NCPFS_MOUNTED_PATH\n"
|
||||
"\n"
|
||||
"Sets the NetWare DOS-info MaximumSpace field through libncp.\n"
|
||||
"LIMIT_4K is in 4 KiB NetWare blocks, matching ncpfs dirlimit.c.\n",
|
||||
prog);
|
||||
"Exercises NetWare directory disk-space NCPs through libncp:\n"
|
||||
" decimal 22/35 / wire 0x23: Get Directory Disk Space Restriction\n"
|
||||
" decimal 22/36 / wire 0x24: Set Directory Disk Space Restriction\n"
|
||||
"LIMIT is in 4 KiB NetWare blocks. LIMIT 0 clears the restriction.\n",
|
||||
prog, prog);
|
||||
}
|
||||
|
||||
static int parse_u32(const char *text, uint32_t *value)
|
||||
{
|
||||
char *end = NULL;
|
||||
unsigned long v;
|
||||
|
||||
errno = 0;
|
||||
v = strtoul(text, &end, 0);
|
||||
if (errno || !end || *end || v > 0xffffffffUL)
|
||||
return -1;
|
||||
*value = (uint32_t)v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void put_u32_le(uint8_t *p, uint32_t value)
|
||||
{
|
||||
p[0] = (uint8_t)(value & 0xffU);
|
||||
p[1] = (uint8_t)((value >> 8) & 0xffU);
|
||||
p[2] = (uint8_t)((value >> 16) & 0xffU);
|
||||
p[3] = (uint8_t)((value >> 24) & 0xffU);
|
||||
}
|
||||
|
||||
static uint32_t get_u32_le(const uint8_t *p)
|
||||
{
|
||||
return ((uint32_t)p[0]) |
|
||||
((uint32_t)p[1] << 8) |
|
||||
((uint32_t)p[2] << 16) |
|
||||
((uint32_t)p[3] << 24);
|
||||
}
|
||||
|
||||
static NWCCODE ncp22_36_set_dirquota(NWCONN_HANDLE conn,
|
||||
NWDIR_HANDLE dirhandle,
|
||||
uint32_t limit4k)
|
||||
{
|
||||
uint8_t rq[5];
|
||||
|
||||
rq[0] = (uint8_t)dirhandle;
|
||||
put_u32_le(rq + 1, limit4k);
|
||||
return NWRequestSimple(conn, NCPC_SFN(22, 36), rq, sizeof(rq), NULL);
|
||||
}
|
||||
|
||||
static NWCCODE ncp22_35_get_dirquota(NWCONN_HANDLE conn,
|
||||
NWDIR_HANDLE dirhandle,
|
||||
struct dirquota_entry *entries,
|
||||
size_t entry_cap,
|
||||
size_t *entry_count)
|
||||
{
|
||||
uint8_t rq[1];
|
||||
uint8_t rpbuf[1024];
|
||||
NW_FRAGMENT rp;
|
||||
NWCCODE err;
|
||||
size_t count;
|
||||
size_t i;
|
||||
|
||||
rq[0] = (uint8_t)dirhandle;
|
||||
memset(rpbuf, 0, sizeof(rpbuf));
|
||||
rp.fragAddr.rw = rpbuf;
|
||||
rp.fragSize = sizeof(rpbuf);
|
||||
|
||||
err = NWRequestSimple(conn, NCPC_SFN(22, 35), rq, sizeof(rq), &rp);
|
||||
if (err)
|
||||
return err;
|
||||
if (rp.fragSize < 1)
|
||||
return 0xff;
|
||||
|
||||
count = rpbuf[0];
|
||||
if (count > entry_cap)
|
||||
count = entry_cap;
|
||||
if (rp.fragSize < 1 + count * 9)
|
||||
return 0xff;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
const uint8_t *p = rpbuf + 1 + i * 9;
|
||||
entries[i].level = p[0];
|
||||
entries[i].max4k = get_u32_le(p + 1);
|
||||
entries[i].current4k = get_u32_le(p + 5);
|
||||
}
|
||||
*entry_count = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -38,46 +132,67 @@ int main(int argc, char **argv)
|
||||
NWDIR_HANDLE dirhandle = 0;
|
||||
NWVOL_NUM volnum = 0;
|
||||
const char *override_path = NULL;
|
||||
const char *mounted_path;
|
||||
unsigned long limit = 0;
|
||||
int set_limit = 0;
|
||||
int opt;
|
||||
const char *mounted_path = NULL;
|
||||
uint32_t set_limit = 0;
|
||||
uint32_t expect_limit = 0;
|
||||
int do_set = 0;
|
||||
int do_get = 0;
|
||||
int do_expect_limit = 0;
|
||||
int do_expect_empty = 0;
|
||||
int i;
|
||||
int len;
|
||||
struct dirquota_entry entries[16];
|
||||
size_t entry_count = 0;
|
||||
|
||||
if (NWCallsInit(NULL, NULL)) {
|
||||
fprintf(stderr, "NWCallsInit failed\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "h?p:l:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'l':
|
||||
errno = 0;
|
||||
limit = strtoul(optarg, NULL, 0);
|
||||
if (errno || limit > 0xffffffffUL) {
|
||||
fprintf(stderr, "invalid limit: %s\n", optarg);
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--set-limit-4k")) {
|
||||
if (++i >= argc || parse_u32(argv[i], &set_limit)) {
|
||||
fprintf(stderr, "invalid limit\n");
|
||||
return 2;
|
||||
}
|
||||
set_limit = 1;
|
||||
break;
|
||||
case 'p':
|
||||
override_path = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
do_set = 1;
|
||||
} else if (!strcmp(argv[i], "--get")) {
|
||||
do_get = 1;
|
||||
} else if (!strcmp(argv[i], "--expect-limit-4k")) {
|
||||
if (++i >= argc || parse_u32(argv[i], &expect_limit)) {
|
||||
fprintf(stderr, "invalid expected limit\n");
|
||||
return 2;
|
||||
}
|
||||
do_get = 1;
|
||||
do_expect_limit = 1;
|
||||
} else if (!strcmp(argv[i], "--expect-empty")) {
|
||||
do_get = 1;
|
||||
do_expect_empty = 1;
|
||||
} else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--path")) {
|
||||
if (++i >= argc) {
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
override_path = argv[i];
|
||||
} else if (argv[i][0] == '-') {
|
||||
fprintf(stderr, "unknown argument: %s\n", argv[i]);
|
||||
usage(argv[0]);
|
||||
return opt == 'h' ? 0 : 2;
|
||||
default:
|
||||
return 2;
|
||||
} else if (!mounted_path) {
|
||||
mounted_path = argv[i];
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!set_limit || optind + 1 != argc) {
|
||||
if (!mounted_path || (!do_set && !do_get) || (do_expect_limit && do_expect_empty)) {
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
mounted_path = argv[optind];
|
||||
|
||||
if (NWCallsInit(NULL, NULL)) {
|
||||
fprintf(stderr, "NWCallsInit failed\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
err = NWParsePath(mounted_path, NULL, &conn, volume, volpath);
|
||||
if (err) {
|
||||
@@ -107,7 +222,7 @@ int main(int argc, char **argv)
|
||||
|
||||
err = ncp_ns_alloc_short_dir_handle(conn, NW_NS_DOS, NCP_DIRSTYLE_NOHANDLE,
|
||||
0, 0, nwpath, len,
|
||||
NCP_ALLOC_TEMPORARY, &dirhandle, &volnum);
|
||||
NCP_ALLOC_PERMANENT, &dirhandle, &volnum);
|
||||
if (err) {
|
||||
fprintf(stderr, "cannot obtain directory handle for %s: %s\n",
|
||||
mounted_path, strnwerror(err));
|
||||
@@ -115,24 +230,63 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
struct ncp_dos_info info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.MaximumSpace = limit;
|
||||
err = ncp_ns_modify_entry_dos_info(conn, NW_NS_DOS, SA_ALL,
|
||||
NCP_DIRSTYLE_HANDLE,
|
||||
volnum, dirhandle, NULL, 0,
|
||||
DM_MAXIMUM_SPACE, &info);
|
||||
if (do_set) {
|
||||
err = ncp22_36_set_dirquota(conn, dirhandle, set_limit);
|
||||
if (err) {
|
||||
fprintf(stderr, "NCP 22/36 set directory quota failed on %s (vol=%u handle=0x%02x): %s\n",
|
||||
mounted_path, (unsigned)volnum, (unsigned)dirhandle, strnwerror(err));
|
||||
ncp_dealloc_dir_handle(conn, dirhandle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
printf("dirquota set path=%s vol=%u handle=0x%02x limit4k=%u\n",
|
||||
mounted_path, (unsigned)volnum, (unsigned)dirhandle,
|
||||
(unsigned)set_limit);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
fprintf(stderr, "cannot set directory quota on %s (vol=%u handle=0x%02x): %s\n",
|
||||
mounted_path, (unsigned)volnum, (unsigned)dirhandle, strnwerror(err));
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
if (do_get) {
|
||||
err = ncp22_35_get_dirquota(conn, dirhandle, entries,
|
||||
sizeof(entries) / sizeof(entries[0]),
|
||||
&entry_count);
|
||||
if (err) {
|
||||
fprintf(stderr, "NCP 22/35 get directory quota failed on %s (vol=%u handle=0x%02x): %s\n",
|
||||
mounted_path, (unsigned)volnum, (unsigned)dirhandle, strnwerror(err));
|
||||
ncp_dealloc_dir_handle(conn, dirhandle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
printf("dirquota get path=%s vol=%u handle=0x%02x entries=%zu\n",
|
||||
mounted_path, (unsigned)volnum, (unsigned)dirhandle, entry_count);
|
||||
for (i = 0; i < (int)entry_count; i++) {
|
||||
uint32_t used = entries[i].max4k >= entries[i].current4k ?
|
||||
entries[i].max4k - entries[i].current4k : 0;
|
||||
printf("dirquota entry%u level=%u max4k=%u current4k=%u used4k=%u\n",
|
||||
(unsigned)i, (unsigned)entries[i].level,
|
||||
(unsigned)entries[i].max4k,
|
||||
(unsigned)entries[i].current4k,
|
||||
(unsigned)used);
|
||||
}
|
||||
|
||||
if (do_expect_empty && entry_count != 0) {
|
||||
fprintf(stderr, "expected no directory quota entries, got %zu\n", entry_count);
|
||||
ncp_dealloc_dir_handle(conn, dirhandle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
if (do_expect_limit) {
|
||||
if (entry_count < 1 || entries[0].max4k != expect_limit) {
|
||||
fprintf(stderr, "expected first directory quota max4k=%u, got %s%u\n",
|
||||
(unsigned)expect_limit,
|
||||
entry_count < 1 ? "no entry, fallback=" : "",
|
||||
entry_count < 1 ? 0U : (unsigned)entries[0].max4k);
|
||||
ncp_dealloc_dir_handle(conn, dirhandle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("directory quota set path=%s limit4k=%lu\n", mounted_path, limit);
|
||||
ncp_dealloc_dir_handle(conn, dirhandle);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
162
tests/nwfs/nwfs_ncpfs_dirquota_smoke.sh.in
Normal file
162
tests/nwfs/nwfs_ncpfs_dirquota_smoke.sh.in
Normal file
@@ -0,0 +1,162 @@
|
||||
#!/bin/sh
|
||||
# Manual NCPFS directory-quota smoke for mars-nwe 3.x quota endpoints.
|
||||
#
|
||||
# Exercises decimal NCP 22/36 (wire/code 0x24) to set a directory disk-space
|
||||
# restriction and decimal NCP 22/35 (wire/code 0x23) to read it back. Host-side
|
||||
# xattr verification checks that the mutation reached netware.metadata.
|
||||
set -eu
|
||||
|
||||
if [ "$#" -lt 4 ]; then
|
||||
echo "usage: $0 SERVER ADMIN PASSWORD HOST_SYSROOT [MOUNTPOINT] [TESTDIR] [VOLUME]" >&2
|
||||
echo "example: $0 MARS SUPERVISOR secret /var/mars_nwe/SYS /mnt/nw-sys NWFSTEST SYS" >&2
|
||||
echo "Set NWFS_NCPFS_DIR_QUOTA_4K to choose the tested limit; default: 12." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
SERVER=$1
|
||||
ADMIN_USER=$2
|
||||
ADMIN_PASSWORD=$3
|
||||
SYSROOT=$4
|
||||
MOUNTPOINT=${5:-}
|
||||
TESTDIR=${6:-${NWFS_NCPFS_TESTDIR:-NWFSTEST}}
|
||||
VOLUME=${7:-${NWFS_NCPFS_VOLUME:-SYS}}
|
||||
DIR_QUOTA_4K=${NWFS_NCPFS_DIR_QUOTA_4K:-12}
|
||||
DIRQUOTA_HELPER="@NWFS_NCPFS_DIRQUOTA_HELPER@"
|
||||
DUMP="@CMAKE_CURRENT_BINARY_DIR@/nwfs_xattr_dump"
|
||||
|
||||
case "$TESTDIR" in
|
||||
/*|*..*|"") echo "TESTDIR must be relative and must not contain '..': $TESTDIR" >&2; exit 2 ;;
|
||||
esac
|
||||
case "$VOLUME" in
|
||||
*:*|*/*|*..*|"") echo "VOLUME must be a bare NetWare volume name: $VOLUME" >&2; exit 2 ;;
|
||||
esac
|
||||
case "$DIR_QUOTA_4K" in
|
||||
''|*[!0-9]*) echo "NWFS_NCPFS_DIR_QUOTA_4K must be an integer 4K block count" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
if [ -z "$DIRQUOTA_HELPER" ] || [ ! -x "$DIRQUOTA_HELPER" ]; then
|
||||
echo "nwfs_ncpfs_dirquota helper not built" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -x "$DUMP" ]; then
|
||||
echo "nwfs_xattr_dump not built: $DUMP" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v ncpmount >/dev/null 2>&1; then
|
||||
echo "ncpmount missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MOUNTPOINT" ]; then
|
||||
MOUNTPOINT=$(mktemp -d "${TMPDIR:-/tmp}/mars-ncpfs-dirquota.XXXXXX")
|
||||
CLEAN_MOUNT=1
|
||||
else
|
||||
mkdir -p "$MOUNTPOINT"
|
||||
CLEAN_MOUNT=0
|
||||
fi
|
||||
|
||||
MOUNTED_BY_SCRIPT=0
|
||||
OUT=$(mktemp "${TMPDIR:-/tmp}/nwfs_dirquota_out.XXXXXX")
|
||||
DUMP_OUT=$(mktemp "${TMPDIR:-/tmp}/nwfs_dirquota_dump.XXXXXX")
|
||||
|
||||
ncpfs_mount_is_active() {
|
||||
mp=$1
|
||||
awk -v mp="$mp" '$2 == mp && $3 == "ncpfs" { found = 1 } END { exit found ? 0 : 1 }' /proc/self/mounts
|
||||
}
|
||||
|
||||
ncpfs_umount_path() {
|
||||
mp=$1
|
||||
if ! ncpfs_mount_is_active "$mp"; then
|
||||
return 0
|
||||
fi
|
||||
if command -v ncpumount >/dev/null 2>&1; then
|
||||
ncpumount "$mp" || umount "$mp"
|
||||
else
|
||||
umount "$mp"
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [ "$MOUNTED_BY_SCRIPT" = 1 ]; then
|
||||
ncpfs_umount_path "$MOUNTPOINT" || true
|
||||
fi
|
||||
if [ "$CLEAN_MOUNT" = 1 ]; then
|
||||
rmdir "$MOUNTPOINT" 2>/dev/null || true
|
||||
fi
|
||||
rm -f "$OUT" "$DUMP_OUT"
|
||||
}
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
purge_testdir_recycle() {
|
||||
for path in "$SYSROOT"/.recycle/*/"$TESTDIR" "$SYSROOT"/.salvage/*/"$TESTDIR"; do
|
||||
[ -e "$path" ] || continue
|
||||
echo "purging old recycle/salvage test remnant $path" >&2
|
||||
rm -rf -- "$path"
|
||||
done
|
||||
}
|
||||
|
||||
mount_admin() {
|
||||
err=$(mktemp "${TMPDIR:-/tmp}/nwfs_dirquota_mount.XXXXXX")
|
||||
ncpfs_umount_path "$MOUNTPOINT"
|
||||
if ! ncpmount -S "$SERVER" -U "$ADMIN_USER" -P "$ADMIN_PASSWORD" -V "$VOLUME" "$MOUNTPOINT" 2>"$err"; then
|
||||
echo "ncpmount failed for //$SERVER/$VOLUME at $MOUNTPOINT" >&2
|
||||
cat "$err" >&2 || true
|
||||
rm -f "$err"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$err"
|
||||
MOUNTED_BY_SCRIPT=1
|
||||
echo "mounted //$SERVER/$VOLUME at $MOUNTPOINT as $ADMIN_USER" >&2
|
||||
}
|
||||
|
||||
verify_dump_limit() {
|
||||
expected=$1
|
||||
"$DUMP" "$SYSROOT/$TESTDIR" | tee "$DUMP_OUT"
|
||||
if [ "$expected" = 0 ]; then
|
||||
if grep -q 'dirQuotaLimit=.*active' "$DUMP_OUT"; then
|
||||
echo "expected directory quota to be cleared on $SYSROOT/$TESTDIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! grep -q "dirQuotaLimit=$expected active" "$DUMP_OUT"; then
|
||||
echo "directory quota metadata did not contain dirQuotaLimit=$expected active on $SYSROOT/$TESTDIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
purge_testdir_recycle
|
||||
mount_admin
|
||||
rm -rf -- "$MOUNTPOINT/$TESTDIR"
|
||||
mkdir -p -- "$MOUNTPOINT/$TESTDIR"
|
||||
sync
|
||||
|
||||
printf '# initial directory quota read should be unrestricted\n'
|
||||
"$DIRQUOTA_HELPER" --expect-empty "$MOUNTPOINT/$TESTDIR" | tee "$OUT"
|
||||
|
||||
printf '# setting directory quota using NCP 22/36 decimal / wire 0x24\n'
|
||||
"$DIRQUOTA_HELPER" --set-limit-4k "$DIR_QUOTA_4K" "$MOUNTPOINT/$TESTDIR" | tee "$OUT"
|
||||
|
||||
printf '# reading directory quota using NCP 22/35 decimal / wire 0x23\n'
|
||||
"$DIRQUOTA_HELPER" --expect-limit-4k "$DIR_QUOTA_4K" "$MOUNTPOINT/$TESTDIR" | tee "$OUT"
|
||||
if ! grep -q "max4k=$DIR_QUOTA_4K" "$OUT"; then
|
||||
echo "NCP 22/35 readback did not report max4k=$DIR_QUOTA_4K" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '# verifying host netware.metadata directory quota\n'
|
||||
verify_dump_limit "$DIR_QUOTA_4K"
|
||||
|
||||
printf '# clearing directory quota using NCP 22/36 decimal / wire 0x24\n'
|
||||
"$DIRQUOTA_HELPER" --set-limit-4k 0 "$MOUNTPOINT/$TESTDIR" | tee "$OUT"
|
||||
|
||||
printf '# reading cleared directory quota using NCP 22/35 decimal / wire 0x23\n'
|
||||
"$DIRQUOTA_HELPER" --expect-empty "$MOUNTPOINT/$TESTDIR" | tee "$OUT"
|
||||
|
||||
printf '# verifying host netware.metadata directory quota clear\n'
|
||||
verify_dump_limit 0
|
||||
|
||||
rm -rf -- "$MOUNTPOINT/$TESTDIR"
|
||||
sync
|
||||
|
||||
echo "directory quota smoke completed for $VOLUME:$TESTDIR limit=${DIR_QUOTA_4K}x4K"
|
||||
Reference in New Issue
Block a user