Files
mars-nwe/tests/linux/afp_smoke_suite.sh
OpenAI 55fdf64c8e
All checks were successful
Source release / source-package (push) Successful in 46s
nwconn: align AFP attribute bits with WebSDK
The WebSDK/NCP AFP File Information records use a distinct SetInfo request bitmap and attribute word.  The previous smoke-oriented implementation reused the low response-bit positions for Set Attributes, Modify Date/Time, FinderInfo, Hidden/Invisible, System, and Archive.  That made the current tests pass, but it was not faithful to the documented header semantics and risked keeping AFP metadata parallel to existing NetWare attributes.

Switch Set File Information to the documented request bitmap values: 0x0100 for Attributes, 0x1000 for Modify Date/Time, and 0x4000 for FinderInfo.  Switch the AFP attribute word to the documented NetWare-style bits: Hidden 0x0200, System 0x0400, Subdirectory 0x1000, and Archive 0x2000.

Map Hidden, System, and Archive through the existing NetWare attribute store via FILE_ATTR_H, FILE_ATTR_S, and FILE_ATTR_A.  This keeps AFP Set/Get/Scan aligned with mars_nwe's existing attribute helper instead of maintaining duplicate AFP-only xattr state.  FinderInfo remains AFP metadata and still uses the Modify-rights gate added earlier.

Update the Linux smoke helper and suite to use --hidden / --clear-hidden while keeping --invisible / --clear-invisible as compatibility aliases.  Document the corrected WebSDK bit values and the convergence rule that NetWare attributes must use mars_nwe NetWare helpers.

Tests: git diff --check; bash -n tests/linux/afp_smoke_suite.sh; gcc -Iinclude -I/mnt/data/stubs -fsyntax-only tests/linux/afp_set_file_info_smoke.c
2026-05-30 17:48:51 +02:00

466 lines
17 KiB
Bash
Executable File

#!/usr/bin/env bash
# Run the mars_nwe AFP Linux smoke helpers as one collectable report.
#
# The helper intentionally keeps the password out of the printed command lines,
# captures AFP server diagnostics from the mars_nwe log while the probes run, and
# appends Linux xattr checks for the tested Unix file.
set -u
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SERVER="MARS"
USER_NAME="SUPERVISOR"
PASSWORD=""
NETWARE_PATH="SYS:PUBLIC/pmdflts.ini"
UNIX_PATH="/var/mars_nwe/SYS/public/pmdflts.ini"
LOG_FILE="/var/log/mars_nwe/nw.log"
OUT_FILE=""
FINDER_TYPE="TEXT"
FINDER_CREATOR="MARS"
TIMESTAMP_EPOCH="1700000000"
READONLY_USER=""
READONLY_PASSWORD=""
READONLY_NO_PASSWORD=0
PREPARE_READONLY_RIGHTS=0
READONLY_RIGHTS="[RF]"
KEEP_GOING=1
CAPTURE_LOG=1
usage() {
cat <<USAGE
Usage: $0 -S SERVER -U USER -P PASSWORD [options]
Options:
--path NETWARE_PATH NetWare path to test (default: $NETWARE_PATH)
--unix-path UNIX_PATH Unix path for getfattr checks (default: $UNIX_PATH)
--log LOGFILE mars_nwe log to tail for AFP lines (default: $LOG_FILE)
--out FILE Write the complete report to FILE as well as stdout
--type FOURCC FinderInfo type written by Set File Info (default: $FINDER_TYPE)
--creator FOURCC FinderInfo creator written by Set File Info (default: $FINDER_CREATOR)
--mtime-epoch SECONDS AFP modify timestamp to write (default: $TIMESTAMP_EPOCH)
--readonly-user USER Optional user expected to lack Modify rights
--readonly-password PASS Password for --readonly-user
--readonly-no-password Use ncpfs -n for --readonly-user
--prepare-readonly-rights Prepare/revoke explicit rights around the negative test
--readonly-rights RIGHTS Rights granted by --prepare-readonly-rights (default: $READONLY_RIGHTS)
--no-log Do not tail/grep the server log
--stop-on-failure Stop after the first failing smoke command
-h, --help Show this help
The script expects the compiled smoke helpers in the same directory as this
script. It prints commands with the password masked, writes an AFP-only log
snippet, and runs getfattr checks for mars_nwe AFP xattrs.
USAGE
}
while [ $# -gt 0 ]; do
case "$1" in
-S|--server)
SERVER=$2; shift 2 ;;
-U|--user)
USER_NAME=$2; shift 2 ;;
-P|--password)
PASSWORD=$2; shift 2 ;;
--path)
NETWARE_PATH=$2; shift 2 ;;
--unix-path)
UNIX_PATH=$2; shift 2 ;;
--log)
LOG_FILE=$2; shift 2 ;;
--out)
OUT_FILE=$2; shift 2 ;;
--type)
FINDER_TYPE=$2; shift 2 ;;
--creator)
FINDER_CREATOR=$2; shift 2 ;;
--mtime-epoch)
TIMESTAMP_EPOCH=$2; shift 2 ;;
--readonly-user)
READONLY_USER=$2; shift 2 ;;
--readonly-password)
READONLY_PASSWORD=$2; READONLY_NO_PASSWORD=0; shift 2 ;;
--readonly-no-password)
READONLY_PASSWORD=""; READONLY_NO_PASSWORD=1; shift ;;
--prepare-readonly-rights)
PREPARE_READONLY_RIGHTS=1; shift ;;
--readonly-rights)
READONLY_RIGHTS=$2; shift 2 ;;
--no-log)
CAPTURE_LOG=0; shift ;;
--stop-on-failure)
KEEP_GOING=0; shift ;;
-h|--help)
usage; exit 0 ;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 2 ;;
esac
done
if [ -z "$PASSWORD" ]; then
echo "Missing password. Use -P PASSWORD." >&2
usage >&2
exit 2
fi
case "$FINDER_TYPE" in
???? ) ;;
*) echo "--type must be exactly four characters" >&2; exit 2 ;;
esac
case "$FINDER_CREATOR" in
???? ) ;;
*) echo "--creator must be exactly four characters" >&2; exit 2 ;;
esac
DIR_PATH=$NETWARE_PATH
case "$NETWARE_PATH" in
*/*) DIR_PATH=${NETWARE_PATH%/*} ;;
esac
REPORT_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-smoke.XXXXXX")
LOG_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-log.XXXXXX")
LOG_PID=""
FAILURES=0
RIGHTS_PREPARED=0
cleanup() {
if [ "$RIGHTS_PREPARED" -eq 1 ] && [ -n "$READONLY_USER" ]; then
nwrevoke -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
-o "$READONLY_USER" -t 1 "$NETWARE_PATH" >/dev/null 2>&1 || true
RIGHTS_PREPARED=0
fi
if [ -n "$LOG_PID" ] && kill -0 "$LOG_PID" 2>/dev/null; then
kill "$LOG_PID" 2>/dev/null || true
wait "$LOG_PID" 2>/dev/null || true
fi
rm -f "$LOG_TMP"
}
trap cleanup EXIT INT TERM
emit() {
printf '%s\n' "$*" | tee -a "$REPORT_TMP"
}
section() {
emit ""
emit "## $*"
}
run_cmd() {
local label=$1
local printable=$2
shift 2
section "$label"
emit "\$ $printable"
"$@" 2>&1 | tee -a "$REPORT_TMP"
local status=${PIPESTATUS[0]}
emit "[exit=$status]"
if [ "$status" -ne 0 ]; then
FAILURES=$((FAILURES + 1))
if [ "$KEEP_GOING" -eq 0 ]; then
finish_report
exit "$status"
fi
fi
}
run_optional_cmd() {
local label=$1
local printable=$2
shift 2
section "$label"
emit "\$ $printable"
"$@" 2>&1 | tee -a "$REPORT_TMP"
local status=${PIPESTATUS[0]}
emit "[exit=$status]"
return "$status"
}
readonly_print_auth() {
if [ "$READONLY_NO_PASSWORD" -eq 1 ]; then
printf '%s' "-n"
else
printf '%s' "-P ******"
fi
}
finish_report() {
if [ "$CAPTURE_LOG" -eq 1 ]; then
sleep 1
if [ -n "$LOG_PID" ] && kill -0 "$LOG_PID" 2>/dev/null; then
kill "$LOG_PID" 2>/dev/null || true
wait "$LOG_PID" 2>/dev/null || true
LOG_PID=""
fi
section "AFP server log excerpt"
if [ -s "$LOG_TMP" ]; then
cat "$LOG_TMP" | tee -a "$REPORT_TMP"
else
emit "No AFP lines captured from $LOG_FILE."
fi
fi
section "Summary"
emit "failures=$FAILURES"
if [ -n "$OUT_FILE" ]; then
cp "$REPORT_TMP" "$OUT_FILE"
emit "report=$OUT_FILE"
fi
}
section "mars_nwe AFP smoke suite"
emit "date=$(date -Is)"
emit "server=$SERVER"
emit "user=$USER_NAME"
emit "path=$NETWARE_PATH"
emit "dir_path=$DIR_PATH"
emit "unix_path=$UNIX_PATH"
emit "log=$LOG_FILE"
emit "finder_type=$FINDER_TYPE"
emit "finder_creator=$FINDER_CREATOR"
emit "mtime_epoch=$TIMESTAMP_EPOCH"
if [ -n "$READONLY_USER" ]; then
emit "readonly_user=$READONLY_USER"
if [ "$READONLY_NO_PASSWORD" -eq 1 ]; then
emit "readonly_auth=no-password"
else
emit "readonly_auth=password"
fi
emit "prepare_readonly_rights=$PREPARE_READONLY_RIGHTS"
emit "readonly_rights=$READONLY_RIGHTS"
fi
for helper in \
afp_entry_id_smoke \
afp_file_info_smoke \
afp_dos_name_smoke \
afp_scan_info_smoke \
afp_temp_dir_handle_smoke \
afp_open_file_fork_smoke \
afp_set_file_info_smoke
do
if [ ! -x "$SCRIPT_DIR/$helper" ]; then
emit "Missing executable: $SCRIPT_DIR/$helper"
exit 2
fi
done
if [ "$CAPTURE_LOG" -eq 1 ]; then
if [ -r "$LOG_FILE" ]; then
# Capture only lines appended while this script is running.
tail -n 0 -F "$LOG_FILE" 2>/dev/null | grep --line-buffered AFP >"$LOG_TMP" &
LOG_PID=$!
sleep 1
else
emit "Log file is not readable, disabling log capture: $LOG_FILE"
CAPTURE_LOG=0
fi
fi
COMMON_PRINT="-S $SERVER -U $USER_NAME -P ******"
if [ -n "$READONLY_USER" ] && [ "$PREPARE_READONLY_RIGHTS" -eq 1 ]; then
# Establish a conservative explicit trustee assignment for the negative
# metadata-write probes. The final nwrevoke below removes only this
# explicit assignment and returns the object to its inherited rights.
run_optional_cmd \
"Prepare readonly trustee cleanup" \
"nwrevoke -S $SERVER -U $USER_NAME -P ****** -o $READONLY_USER -t 1 '$NETWARE_PATH'" \
nwrevoke -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
-o "$READONLY_USER" -t 1 "$NETWARE_PATH" || true
run_cmd \
"Prepare readonly trustee rights" \
"nwgrant -S $SERVER -U $USER_NAME -P ****** -o $READONLY_USER -t 1 -r '$READONLY_RIGHTS' '$NETWARE_PATH'" \
nwgrant -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
-o "$READONLY_USER" -t 1 -r "$READONLY_RIGHTS" "$NETWARE_PATH"
RIGHTS_PREPARED=1
fi
run_cmd \
"AFP Entry ID From Path Name" \
"./afp_entry_id_smoke $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_entry_id_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP Entry ID From NetWare Handle" \
"./afp_entry_id_smoke --from-handle $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_entry_id_smoke" --from-handle -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP 2.0 Get File Information" \
"./afp_file_info_smoke $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP Get DOS Name From Entry ID" \
"./afp_dos_name_smoke $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_dos_name_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP 2.0 Scan File Information" \
"./afp_scan_info_smoke $COMMON_PRINT '$DIR_PATH'" \
"$SCRIPT_DIR/afp_scan_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$DIR_PATH"
run_cmd \
"AFP Alloc Temporary Directory Handle" \
"./afp_temp_dir_handle_smoke $COMMON_PRINT '$DIR_PATH'" \
"$SCRIPT_DIR/afp_temp_dir_handle_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$DIR_PATH"
run_cmd \
"AFP Open File Fork" \
"./afp_open_file_fork_smoke $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_open_file_fork_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP Open File Fork write access rejected" \
"./afp_open_file_fork_smoke --expect-completion 0x84 --access 0x02 $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_open_file_fork_smoke" --expect-completion 0x84 --access 0x02 \
-S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP Open File Fork resource fork rejected" \
"./afp_open_file_fork_smoke --expect-completion 0x9c --fork 1 $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_open_file_fork_smoke" --expect-completion 0x9c --fork 1 \
-S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information FinderInfo" \
"./afp_set_file_info_smoke $COMMON_PRINT --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information FinderInfo legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--afp09 --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Hidden" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear Hidden" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --clear-hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --clear-hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Hidden legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --attributes-only --hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--afp09 --attributes-only --hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear Hidden legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --attributes-only --clear-hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--afp09 --attributes-only --clear-hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Modify Timestamp" \
"./afp_set_file_info_smoke $COMMON_PRINT --timestamp-only --mtime-epoch '$TIMESTAMP_EPOCH' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--timestamp-only --mtime-epoch "$TIMESTAMP_EPOCH" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information System" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --system '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --system "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear System" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --clear-system '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --clear-system "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Archive" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --archive '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --archive "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear Archive" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --clear-archive '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --clear-archive "$NETWARE_PATH"
if [ -n "$READONLY_USER" ]; then
READONLY_PRINT="-S $SERVER -U $READONLY_USER $(readonly_print_auth)"
if [ "$READONLY_NO_PASSWORD" -eq 1 ]; then
READONLY_AUTH_ARGS=(-n)
else
READONLY_AUTH_ARGS=(-P "$READONLY_PASSWORD")
fi
run_cmd \
"AFP metadata Modify rights rejected: FinderInfo" \
"./afp_set_file_info_smoke --expect-completion 0x8c $READONLY_PRINT --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" --expect-completion 0x8c \
-S "$SERVER" -U "$READONLY_USER" "${READONLY_AUTH_ARGS[@]}" \
--finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP attribute Modify rights rejected: Hidden" \
"./afp_set_file_info_smoke --expect-completion 0x8c $READONLY_PRINT --attributes-only --hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" --expect-completion 0x8c \
-S "$SERVER" -U "$READONLY_USER" "${READONLY_AUTH_ARGS[@]}" \
--attributes-only --hidden "$NETWARE_PATH"
run_cmd \
"AFP metadata Modify rights rejected: System" \
"./afp_set_file_info_smoke --expect-completion 0x8c $READONLY_PRINT --attributes-only --system '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" --expect-completion 0x8c \
-S "$SERVER" -U "$READONLY_USER" "${READONLY_AUTH_ARGS[@]}" \
--attributes-only --system "$NETWARE_PATH"
fi
if [ -n "$READONLY_USER" ] && [ "$PREPARE_READONLY_RIGHTS" -eq 1 ]; then
run_cmd \
"Restore readonly trustee assignment" \
"nwrevoke -S $SERVER -U $USER_NAME -P ****** -o $READONLY_USER -t 1 '$NETWARE_PATH'" \
nwrevoke -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
-o "$READONLY_USER" -t 1 "$NETWARE_PATH"
RIGHTS_PREPARED=0
fi
if command -v stat >/dev/null 2>&1; then
run_cmd \
"Linux stat: AFP Modify Timestamp" \
"stat -c 'mtime_epoch=%Y mtime=%y' '$UNIX_PATH'" \
stat -c 'mtime_epoch=%Y mtime=%y' "$UNIX_PATH"
fi
if command -v getfattr >/dev/null 2>&1; then
run_cmd \
"Linux xattr: AFP FinderInfo" \
"getfattr -n user.org.mars-nwe.afp.finder-info -e hex '$UNIX_PATH'" \
getfattr -n user.org.mars-nwe.afp.finder-info -e hex "$UNIX_PATH"
run_cmd \
"Linux xattr: AFP Attributes" \
"getfattr -n user.org.mars-nwe.afp.attributes -e hex '$UNIX_PATH'" \
getfattr -n user.org.mars-nwe.afp.attributes -e hex "$UNIX_PATH"
run_cmd \
"Linux xattr: AFP Entry ID" \
"getfattr -n user.org.mars-nwe.afp.entry-id -e hex '$UNIX_PATH'" \
getfattr -n user.org.mars-nwe.afp.entry-id -e hex "$UNIX_PATH"
else
section "Linux xattr checks"
emit "getfattr not found; install the attr package to collect xattr output."
FAILURES=$((FAILURES + 1))
fi
finish_report
if [ "$FAILURES" -ne 0 ]; then
exit 1
fi
exit 0