tests: add DOS quota write-deny smoke

This commit is contained in:
OpenAI
2026-06-12 08:12:30 +00:00
committed by Mario Fetka
parent e5e2c4d029
commit 77bd01026c
9 changed files with 306 additions and 3 deletions

View File

@@ -51,6 +51,7 @@ set(MARS_DOSUTILS_NEW_ONLY_TOOLS
creator
whoami
ncopy
tests
)
if(MARS_DOSUTILS_BUILD_FROM_SOURCE)

View File

@@ -727,3 +727,5 @@ Prints the effective-rights values returned by several Client32/NCP paths for co
`TESTS EFFRIGHT path` also prints exploratory old NCP22 effective-rights call variants for comparing with Novell RIGHTS.
`TESTS EFFRIGHT path` additionally tests NCP22 subfunction 50 object effective rights using the current login object id.
`TESTS WRITE4K file [count]` writes one or more exact 4K blocks and returns non-zero if open/write/close fails. It is used by the DOS quota smoke to prove that the 13th 4K write is denied after Linux/MARS-NWE set a 12x4K user quota.

View File

@@ -25,6 +25,11 @@
#include "net.h"
#include "ncpapi.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <io.h>
#include <errno.h>
#define TEST_RIGHT_S 0x01
#define TEST_RIGHT_R 0x02
@@ -55,6 +60,7 @@ static void tests_usage(void)
fprintf(stdout, " TESTS NCP2225CREATE file [date time id] (create xattr metadata)\n");
fprintf(stdout, " TESTS NCP2225MODID file [id] (modifier-id xattr metadata)\n");
fprintf(stdout, " TESTS NCP2225MAXSPACE dir [blocks] (directory maximum-space/quota)\n");
fprintf(stdout, " TESTS WRITE4K file [count] (write count 4K blocks; default 1)\n");
fprintf(stdout, " TESTS NCP221EINFO dir (dump NCP22/1E directory info layout)\n");
fprintf(stdout, " TESTS NCP22S4 path RF|42|0x42|ALL|NONE\n");
fprintf(stdout, " TESTS NCP22REN oldpath newpath (NCP22/2E Rename Or Move old)\n");
@@ -1236,6 +1242,68 @@ static int tests_ncp2225adate(char *path, char *date_arg)
static int tests_parse_int_arg(char *s, int *value_out)
{
long v;
char *end;
if (!s || !*s || !value_out)
return(-1);
v = strtol(s, &end, 0);
if (!end || *end || v < 1 || v > 32767L)
return(-1);
*value_out = (int)v;
return(0);
}
static int tests_write4k(char *path, char *count_arg)
{
char buf[4096];
int count = 1;
int fd;
int i;
if (!path || !*path) {
fprintf(stdout, "Usage: TESTS WRITE4K file [count]\n");
return(1);
}
if (count_arg && tests_parse_int_arg(count_arg, &count)) {
fprintf(stdout, "Bad WRITE4K count '%s'. Use a positive decimal/hex number.\n", count_arg);
return(1);
}
memset(buf, 'Q', sizeof(buf));
fd = open(path, O_BINARY | O_RDWR | O_CREAT | O_TRUNC | O_DENYNONE,
S_IREAD | S_IWRITE);
if (fd < 0) {
fprintf(stdout, "WRITE4K open failed path=%s errno=%d\n", path, errno);
return(2);
}
for (i = 0; i < count; i++) {
unsigned written = 0;
if (_dos_write(fd, buf, sizeof(buf), &written) || written != sizeof(buf)) {
fprintf(stdout, "WRITE4K write failed path=%s block=%d/%d written=%u errno=%d\n",
path, i + 1, count, written, errno);
close(fd);
return(3);
}
}
if (close(fd)) {
fprintf(stdout, "WRITE4K close failed path=%s errno=%d\n", path, errno);
return(4);
}
fprintf(stdout, "WRITE4K ok path=%s blocks=%d bytes=%ld\n",
path, count, (long)count * 4096L);
return(0);
}
static int tests_ncp2225maxspace(char *path, char *space_arg)
{
uint8 dhandle = 0;
@@ -2669,6 +2737,14 @@ int func_tests(int argc, char *argv[], int mode)
return tests_ncp2225adate(argv[2], argv[3]);
}
if (tool_strsame(argv[1], "WRITE4K")) {
if (argc < 3)
return tests_write4k(NULL, NULL);
if (argc < 4)
return tests_write4k(argv[2], NULL);
return tests_write4k(argv[2], argv[3]);
}
if (tool_strsame(argv[1], "NCP2225MAXSPACE")) {
if (argc < 3)
return tests_ncp2225maxspace(NULL, NULL);

View File

@@ -72,6 +72,7 @@ script or log.
| `rightsuser/` | varies | Additional user-rights experiments. |
| `renmove/` | varies | Rename/move experiments. |
| `ncopy/` | varies | NCOPY experiments. |
| `quota/` | `DQTSTA.BAT` + `DQTC.BAT` | Mixed Linux/DOS userquota write-deny smoke: Linux sets quota, DOS writes until deny. |
| `filer/` | varies | FILER-related notes/experiments. |
## Host-side NSS/OES metadata readback
@@ -84,7 +85,7 @@ sh dosutils/test/cmnwmeta.sh /path/to/SYS /path/to/nwfs_xattr_dump > meta.log
```
The collector decodes `netware.metadata`, `netware.quota`, and
`netware.userquota` from the files and directories changed by the DOS tests.
`netware.userquota.0` from the files and directories changed by the DOS tests.
This is the expected verification layer for the NSS migration: DOS tools or
NCPFS perform the mutation, and `nwfs_xattr_dump` proves that the resulting
state landed in the OES-compatible `netware.*` metadata rather than only in the

View File

@@ -5,7 +5,7 @@
# sh dosutils/test/cmnwmeta.sh /path/to/SYS /path/to/nwfs_xattr_dump > meta.log
#
# The dumper reads the mars-nwe userspace xattr mapping, so on Linux it looks
# at user.netware.metadata, user.netware.quota and user.netware.userquota.
# at user.netware.metadata, user.netware.quota and user.netware.userquota.0.
set -eu
@@ -44,7 +44,8 @@ for rel in \
NDIRTST NDIRCMP \
TFILE \
NCPTST NCPCMP \
RUTEST RUTCMP
RUTEST RUTCMP \
DQTTEST DQTCMP
do
if [ -e "$SYSROOT/$rel" ]; then
find "$SYSROOT/$rel" -xdev \( -type f -o -type d \) -print

61
test/quota/DQTC.BAT Normal file
View File

@@ -0,0 +1,61 @@
@ECHO OFF
REM DQTC.BAT
REM Run as NOPASSUSER after Linux-side quota setup.
F:
CD \
IF NOT EXIST DQTCMP\NUL MD DQTCMP
IF NOT EXIST DQTCMP\DOS\NUL MD DQTCMP\DOS
IF NOT EXIST DQTTEST\NCPQFILL\NUL MD DQTTEST\NCPQFILL
IF EXIST F:\DQTCMP\PASS.TAG DEL F:\DQTCMP\PASS.TAG
IF EXIST F:\DQTCMP\FAIL.TAG DEL F:\DQTCMP\FAIL.TAG
IF EXIST F:\DQTCMP\DOS\WRITE.LOG DEL F:\DQTCMP\DOS\WRITE.LOG
ECHO DQTC DOS quota write test as current user > F:\DQTCMP\DOS\WRITE.LOG
ECHO Writing 12 allowed 4K files. >> F:\DQTCMP\DOS\WRITE.LOG
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00001.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00002.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00003.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00004.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00005.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00006.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00007.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00008.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00009.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00010.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00011.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\Q00012.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO FAILGOOD
ECHO Attempting expected failing 13th 4K file. >> F:\DQTCMP\DOS\WRITE.LOG
PUBLIC\TESTS WRITE4K F:\DQTTEST\NCPQFILL\QFAIL.BIN 1 >> F:\DQTCMP\DOS\WRITE.LOG
IF ERRORLEVEL 1 GOTO PASS
ECHO FAIL: expected QFAIL.BIN to be denied, but it succeeded. >> F:\DQTCMP\DOS\WRITE.LOG
ECHO FAIL > F:\DQTCMP\FAIL.TAG
GOTO END
:FAILGOOD
ECHO FAIL: an allowed 4K write failed before the quota boundary. >> F:\DQTCMP\DOS\WRITE.LOG
ECHO FAIL > F:\DQTCMP\FAIL.TAG
GOTO END
:PASS
ECHO PASS: 13th 4K file was denied. >> F:\DQTCMP\DOS\WRITE.LOG
ECHO PASS > F:\DQTCMP\PASS.TAG
GOTO END
:END
TYPE F:\DQTCMP\DOS\WRITE.LOG

87
test/quota/DQTSTA.BAT Normal file
View File

@@ -0,0 +1,87 @@
@ECHO OFF
REM DQTSTA.BAT
REM DOS-side quota write-deny smoke for MARS-NWE.
REM
REM This is intentionally a mixed Linux/DOS test:
REM 1. Run DQTSTA PREP as SUPERVISOR from the target volume.
REM 2. On Linux set the volume userquota for NOPASSUSER.
REM 3. Login as NOPASSUSER and run DQTC.BAT from this directory.
REM 4. Login as SUPERVISOR and run DQTSTA PART2, then DQTZIP.
IF "%1"=="" GOTO PREP
IF "%1"=="PREP" GOTO PREP
IF "%1"=="prep" GOTO PREP
IF "%1"=="PART2" GOTO PART2
IF "%1"=="part2" GOTO PART2
ECHO Usage: DQTSTA [PREP^|PART2]
GOTO END
:PREP
F:
CD \
IF EXIST DQTTEST\NUL DELTREE /Y DQTTEST\*.*
IF EXIST DQTCMP\NUL DELTREE /Y DQTCMP\*.*
IF NOT EXIST DQTTEST\NUL MD DQTTEST
IF NOT EXIST DQTTEST\NCPQFILL\NUL MD DQTTEST\NCPQFILL
IF NOT EXIST DQTCMP\NUL MD DQTCMP
IF NOT EXIST DQTCMP\DOS\NUL MD DQTCMP\DOS
IF NOT EXIST DQTCMP\SETUP\NUL MD DQTCMP\SETUP
IF EXIST F:\DQTCMP\RUN.LOG DEL F:\DQTCMP\RUN.LOG
IF EXIST F:\DQTCMP\SUMMARY.TXT DEL F:\DQTCMP\SUMMARY.TXT
IF EXIST F:\DQTCMP\FAIL.TAG DEL F:\DQTCMP\FAIL.TAG
IF EXIST F:\DQTCMP\PASS.TAG DEL F:\DQTCMP\PASS.TAG
IF EXIST F:\DQTCMP\DQTSTA.ZIP DEL F:\DQTCMP\DQTSTA.ZIP
IF EXIST F:\DQTCMP\ZIP.LOG DEL F:\DQTCMP\ZIP.LOG
IF EXIST F:\DQTCMP\DOS\*.OUT DEL F:\DQTCMP\DOS\*.OUT
ECHO DQTSTA DOS quota write-deny smoke > F:\DQTCMP\RUN.LOG
ECHO Volume-side setup is done from DOS. Quota limit is set from Linux. >> F:\DQTCMP\RUN.LOG
ECHO Expected Linux setup: userquota for NOPASSUSER allows 12x4K, then DOS write 13th file fails. >> F:\DQTCMP\RUN.LOG
ECHO. >> F:\DQTCMP\RUN.LOG
REM Give the normal user enough rights to create files and write result logs.
IF EXIST F:\NPUBLIC\GRANT.EXE GOTO HAVEGRANT
ECHO ERROR: F:\NPUBLIC\GRANT.EXE not found. >> F:\DQTCMP\RUN.LOG
ECHO ERROR: F:\NPUBLIC\GRANT.EXE not found.
GOTO END
:HAVEGRANT
NPUBLIC\GRANT R W C E M F A FOR F:\DQTTEST TO USER NOPASSUSER > F:\DQTCMP\SETUP\GRANT1.OUT
NPUBLIC\GRANT R W C E M F A FOR F:\DQTTEST\NCPQFILL TO USER NOPASSUSER > F:\DQTCMP\SETUP\GRANT2.OUT
NPUBLIC\GRANT R W C E M F A FOR F:\DQTCMP TO USER NOPASSUSER > F:\DQTCMP\SETUP\GRANT3.OUT
NPUBLIC\RIGHTS F:\DQTTEST\NCPQFILL > F:\DQTCMP\SETUP\RIGHTS.OUT
ECHO === NEXT LINUX STEP === > F:\DQTCMP\LINUX.TXT
ECHO Set volume userquota for NOPASSUSER to 12x4K on this volume. >> F:\DQTCMP\LINUX.TXT
ECHO Then login as NOPASSUSER and run: >> F:\DQTCMP\LINUX.TXT
ECHO F:\DQTC.BAT >> F:\DQTCMP\LINUX.TXT
ECHO Then login as SUPERVISOR and run: >> F:\DQTCMP\LINUX.TXT
ECHO F:\DQTSTA.BAT PART2 >> F:\DQTCMP\LINUX.TXT
ECHO DQTSTA PREP finished. >> F:\DQTCMP\RUN.LOG
ECHO.
ECHO DQTSTA PREP fertig.
ECHO Jetzt Linux quota fuer NOPASSUSER setzen, dann als NOPASSUSER F:\DQTC.BAT starten.
GOTO END
:PART2
F:
CD \
IF NOT EXIST DQTCMP\NUL MD DQTCMP
ECHO DQTSTA PART2 summary > F:\DQTCMP\SUMMARY.TXT
IF EXIST F:\DQTCMP\PASS.TAG ECHO PASS: DOS quota deny observed. >> F:\DQTCMP\SUMMARY.TXT
IF EXIST F:\DQTCMP\FAIL.TAG ECHO FAIL: DOS quota deny was not observed. >> F:\DQTCMP\SUMMARY.TXT
IF NOT EXIST F:\DQTCMP\PASS.TAG IF NOT EXIST F:\DQTCMP\FAIL.TAG ECHO UNKNOWN: DQTC.BAT result tags missing. >> F:\DQTCMP\SUMMARY.TXT
ECHO. >> F:\DQTCMP\SUMMARY.TXT
ECHO DOS log files are in F:\DQTCMP\DOS. >> F:\DQTCMP\SUMMARY.TXT
ECHO Linux/nw.log evidence should be collected with the matching mars-nwe smoke wrapper. >> F:\DQTCMP\SUMMARY.TXT
ECHO.
TYPE F:\DQTCMP\SUMMARY.TXT
ECHO Optional: run DQTZIP.
GOTO END
:END

19
test/quota/DQTZIP.BAT Normal file
View File

@@ -0,0 +1,19 @@
@ECHO OFF
REM DQTZIP.BAT
REM Optional packer for DOS quota smoke result files.
F:
CD \DQTCMP
IF EXIST DQTSTA.ZIP DEL DQTSTA.ZIP
IF EXIST ZIP.LOG DEL ZIP.LOG
ECHO Creating DQTSTA.ZIP > ZIP.LOG
ZIP -r DQTSTA.ZIP RUN.LOG SUMMARY.TXT LINUX.TXT PASS.TAG FAIL.TAG DOS SETUP >> ZIP.LOG
ECHO.
ECHO ZIP step finished.
ECHO Check:
ECHO F:\DQTCMP\DQTSTA.ZIP
ECHO F:\DQTCMP\ZIP.LOG
ECHO.

55
test/quota/README.md Normal file
View File

@@ -0,0 +1,55 @@
# DOS quota write-deny smoke
This test proves the last step of NetWare-style quota enforcement with DOS
board tools: Linux/NCPFS sets the user quota, then a real DOS client logs in as
`NOPASSUSER` and attempts the file writes.
It is intentionally split because the authoritative quota setup remains on the
Linux/MARS-NWE side:
1. In DOS, login as `SUPERVISOR` on the target volume and run:
```bat
F:
DQTSTA PREP
```
This creates `F:\DQTTEST\NCPQFILL`, grants `NOPASSUSER` write/create rights,
and creates `F:\DQTCMP` for logs.
2. On Linux, set the user quota for `NOPASSUSER` to 12 4K blocks on the same
volume. With the mars-nwe ncpfs helper this is typically:
```sh
./nwfs_ncpfs_userquota -S MARS -U SUPERVISOR -P 'password' \
--volume QUOTA --object NOPASSUSER --type 1 --limit-4k 12
```
For SYS/NWQUOTA metadata-backend testing, use `--volume SYS` instead.
3. In DOS, login as `NOPASSUSER` and run:
```bat
F:\DQTC.BAT
```
`DQTC` writes `Q00001.BIN` through `Q00012.BIN` as 4K files, then expects
`QFAIL.BIN` to be denied.
4. In DOS, login as `SUPERVISOR` and run:
```bat
F:\DQTSTA PART2
F:\DQTZIP
```
Expected result:
```text
PASS: DOS quota deny observed.
```
The test does not set quotas itself. That keeps the authority split explicit:
Linuxquota volumes are configured/enforced by the Linux backend, while NWQUOTA
metadata volumes use the MARS-NWE metadata backend. The DOS part proves the
client-visible write behavior.