#!/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" CREATE_DIR_NAME="" CREATE_FILE_NAME="" READONLY_USER="" READONLY_PASSWORD="" READONLY_NO_PASSWORD=0 PREPARE_READONLY_RIGHTS=0 READONLY_RIGHTS="[RF]" KEEP_GOING=1 CAPTURE_LOG=1 LOG_WINDOW_SECONDS=120 RENAME_DIR_NAME="" RENAME_FILE_NAME="" usage() { cat <&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 case "$CREATE_DIR_NAME" in ""|*/*|*\\*|*:*) echo "--create-dir-name must be a single path component" >&2; exit 2 ;; esac case "$CREATE_FILE_NAME" in ""|*/*|*\\*|*:*) echo "--create-file-name must be a single path component" >&2; exit 2 ;; esac case "$LOG_WINDOW_SECONDS" in ''|*[!0-9]*) echo "--log-window-seconds must be a positive integer" >&2; exit 2 ;; esac if [ "$LOG_WINDOW_SECONDS" -le 0 ]; then echo "--log-window-seconds must be greater than zero" >&2 exit 2 fi if [ -z "$CREATE_DIR_NAME" ]; then CREATE_DIR_NAME=$(date +a%H%M%S) fi if [ -z "$CREATE_FILE_NAME" ]; then CREATE_FILE_NAME=$(printf 'f%04d%01d' "$((10#$(date +%H%M) % 10000))" "$((RANDOM % 10))") fi if [ -z "$RENAME_DIR_NAME" ]; then RENAME_DIR_NAME=$(printf 'd%04d%01d' "$((10#$(date +%H%M) % 10000))" "$((RANDOM % 10))") fi if [ -z "$RENAME_FILE_NAME" ]; then RENAME_FILE_NAME=$(printf 'm%04d%01d' "$((10#$(date +%H%M) % 10000))" "$((RANDOM % 10))") fi case "$CREATE_DIR_NAME" in ???????|??????|?????|????|???|??|?) ;; *) echo "--create-dir-name must be at most seven characters so the AFP 2.0 companion name stays DOS-compatible" >&2; exit 2 ;; esac case "$CREATE_FILE_NAME" in ???????|??????|?????|????|???|??|?) ;; *) echo "--create-file-name must be at most seven characters so the AFP 2.0 companion name stays DOS-compatible" >&2; exit 2 ;; esac case "$RENAME_DIR_NAME" in ???????|??????|?????|????|???|??|?) ;; *) echo "--rename-dir-name must be at most seven characters" >&2; exit 2 ;; esac case "$RENAME_FILE_NAME" in ???????|??????|?????|????|???|??|?) ;; *) echo "--rename-file-name must be at most seven characters" >&2; exit 2 ;; esac DIR_PATH=$NETWARE_PATH case "$NETWARE_PATH" in */*) DIR_PATH=${NETWARE_PATH%/*} ;; esac CREATE_DIR_PATH="$DIR_PATH/$CREATE_DIR_NAME" CREATE_DIR20_PATH="$DIR_PATH/${CREATE_DIR_NAME}2" UNIX_PARENT_PATH=$(dirname -- "$UNIX_PATH") CREATE_DIR_NAME_DOS=$(printf '%s' "$CREATE_DIR_NAME" | tr '[:lower:]' '[:upper:]') CREATE_DIR20_NAME_DOS=$(printf '%s' "${CREATE_DIR_NAME}2" | tr '[:lower:]' '[:upper:]') UNIX_DIR_PATH=$UNIX_PARENT_PATH/$CREATE_DIR_NAME UNIX_DIR20_PATH=$UNIX_PARENT_PATH/${CREATE_DIR_NAME}2 UNIX_DIR_PATH_DOS=$UNIX_PARENT_PATH/$CREATE_DIR_NAME_DOS UNIX_DIR20_PATH_DOS=$UNIX_PARENT_PATH/$CREATE_DIR20_NAME_DOS CREATE_FILE_PATH="$DIR_PATH/$CREATE_FILE_NAME" CREATE_FILE20_PATH="$DIR_PATH/${CREATE_FILE_NAME}2" CREATE_FILE_NAME_DOS=$(printf '%s' "$CREATE_FILE_NAME" | tr '[:lower:]' '[:upper:]') CREATE_FILE20_NAME_DOS=$(printf '%s' "${CREATE_FILE_NAME}2" | tr '[:lower:]' '[:upper:]') UNIX_FILE_PATH=$UNIX_PARENT_PATH/$CREATE_FILE_NAME UNIX_FILE20_PATH=$UNIX_PARENT_PATH/${CREATE_FILE_NAME}2 UNIX_FILE_PATH_DOS=$UNIX_PARENT_PATH/$CREATE_FILE_NAME_DOS UNIX_FILE20_PATH_DOS=$UNIX_PARENT_PATH/$CREATE_FILE20_NAME_DOS RENAME_DIR_FROM_PATH="$DIR_PATH/$RENAME_DIR_NAME" RENAME_DIR_TO_PATH="$DIR_PATH/${RENAME_DIR_NAME}r" RENAME_FILE_FROM_PATH="$DIR_PATH/$RENAME_FILE_NAME" RENAME_FILE_TO_PATH="$DIR_PATH/${RENAME_FILE_NAME}r" REPORT_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-smoke.XXXXXX") LOG_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-log.XXXXXX") LOG_RECENT_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-log-recent.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" "$LOG_RECENT_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 } cleanup_created_dir() { local path=$1 local dos_path=$2 if [ -d "$path" ]; then rmdir "$path" elif [ -d "$dos_path" ]; then rmdir "$dos_path" else rmdir "$path" fi } cleanup_created_file() { local path=$1 local dos_path=$2 if [ -f "$path" ]; then rm -f "$path" elif [ -f "$dos_path" ]; then rm -f "$dos_path" else rm -f "$path" 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 } capture_recent_afp_log() { local cutoff : >"$LOG_RECENT_TMP" if [ ! -r "$LOG_FILE" ]; then return 1 fi cutoff=$(date -d "@$(( $(date +%s) - LOG_WINDOW_SECONDS ))" '+%m.%d,%H:%M:%S' 2>/dev/null) || return 1 awk -v cutoff="$cutoff" ' /AFP/ { ts = substr($0, 1, 14) if (ts >= cutoff) print } ' "$LOG_FILE" >"$LOG_RECENT_TMP" } 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" emit "recent_window_seconds=$LOG_WINDOW_SECONDS" if capture_recent_afp_log && [ -s "$LOG_RECENT_TMP" ]; then cat "$LOG_RECENT_TMP" | tee -a "$REPORT_TMP" elif [ -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 "log_window_seconds=$LOG_WINDOW_SECONDS" emit "finder_type=$FINDER_TYPE" emit "finder_creator=$FINDER_CREATOR" emit "mtime_epoch=$TIMESTAMP_EPOCH" emit "create_dir_path=$CREATE_DIR_PATH" emit "create_dir20_path=$CREATE_DIR20_PATH" emit "unix_dir_path=$UNIX_DIR_PATH" emit "unix_dir20_path=$UNIX_DIR20_PATH" emit "unix_dir_path_dos=$UNIX_DIR_PATH_DOS" emit "unix_dir20_path_dos=$UNIX_DIR20_PATH_DOS" emit "create_file_path=$CREATE_FILE_PATH" emit "create_file20_path=$CREATE_FILE20_PATH" emit "rename_dir_from_path=$RENAME_DIR_FROM_PATH" emit "rename_dir_to_path=$RENAME_DIR_TO_PATH" emit "rename_file_from_path=$RENAME_FILE_FROM_PATH" emit "rename_file_to_path=$RENAME_FILE_TO_PATH" emit "unix_file_path=$UNIX_FILE_PATH" emit "unix_file20_path=$UNIX_FILE20_PATH" emit "unix_file_path_dos=$UNIX_FILE_PATH_DOS" emit "unix_file20_path_dos=$UNIX_FILE20_PATH_DOS" 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_create_directory_smoke \ afp_create_file_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" if [ -d "$UNIX_DIR_PATH" ] || [ -d "$UNIX_DIR_PATH_DOS" ]; then run_optional_cmd \ "Prepare AFP Create Directory cleanup" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_DIR_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_DIR_PATH" || true fi if [ -d "$UNIX_DIR20_PATH" ] || [ -d "$UNIX_DIR20_PATH_DOS" ]; then run_optional_cmd \ "Prepare AFP 2.0 Create Directory cleanup" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_DIR20_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_DIR20_PATH" || true fi run_cmd \ "AFP Create Directory" \ "./afp_create_directory_smoke $COMMON_PRINT '$CREATE_DIR_PATH'" \ "$SCRIPT_DIR/afp_create_directory_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_DIR_PATH" run_cmd \ "AFP 2.0 Create Directory" \ "./afp_create_directory_smoke --afp20 $COMMON_PRINT '$CREATE_DIR20_PATH'" \ "$SCRIPT_DIR/afp_create_directory_smoke" --afp20 \ -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_DIR20_PATH" run_cmd \ "AFP Delete Created Directory" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_DIR_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_DIR_PATH" run_cmd \ "AFP Delete Created 2.0 Directory" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_DIR20_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_DIR20_PATH" if [ -f "$UNIX_FILE_PATH" ] || [ -f "$UNIX_FILE_PATH_DOS" ]; then run_optional_cmd \ "Prepare AFP Create File cleanup" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_FILE_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_FILE_PATH" || true fi if [ -f "$UNIX_FILE20_PATH" ] || [ -f "$UNIX_FILE20_PATH_DOS" ]; then run_optional_cmd \ "Prepare AFP 2.0 Create File cleanup" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_FILE20_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_FILE20_PATH" || true fi run_cmd \ "AFP Create File" \ "./afp_create_file_smoke $COMMON_PRINT '$CREATE_FILE_PATH'" \ "$SCRIPT_DIR/afp_create_file_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_FILE_PATH" run_cmd \ "AFP 2.0 Create File" \ "./afp_create_file_smoke --afp20 $COMMON_PRINT '$CREATE_FILE20_PATH'" \ "$SCRIPT_DIR/afp_create_file_smoke" --afp20 \ -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_FILE20_PATH" run_cmd \ "AFP Delete Created File" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_FILE_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_FILE_PATH" run_cmd \ "AFP Delete Created 2.0 File" \ "./afp_delete_smoke $COMMON_PRINT '$CREATE_FILE20_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$CREATE_FILE20_PATH" run_optional_cmd \ "Prepare AFP Rename Directory cleanup source" \ "./afp_delete_smoke $COMMON_PRINT '$RENAME_DIR_FROM_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_DIR_FROM_PATH" || true run_optional_cmd \ "Prepare AFP Rename Directory cleanup destination" \ "./afp_delete_smoke $COMMON_PRINT '$RENAME_DIR_TO_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_DIR_TO_PATH" || true run_cmd \ "AFP Rename Directory create source" \ "./afp_create_directory_smoke $COMMON_PRINT '$RENAME_DIR_FROM_PATH'" \ "$SCRIPT_DIR/afp_create_directory_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_DIR_FROM_PATH" run_cmd \ "AFP Rename Directory" \ "./afp_rename_smoke $COMMON_PRINT '$RENAME_DIR_FROM_PATH' '$RENAME_DIR_TO_PATH'" \ "$SCRIPT_DIR/afp_rename_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_DIR_FROM_PATH" "$RENAME_DIR_TO_PATH" run_cmd \ "AFP Rename Directory cleanup" \ "./afp_delete_smoke $COMMON_PRINT '$RENAME_DIR_TO_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_DIR_TO_PATH" run_optional_cmd \ "Prepare AFP Rename File cleanup source" \ "./afp_delete_smoke $COMMON_PRINT '$RENAME_FILE_FROM_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_FILE_FROM_PATH" || true run_optional_cmd \ "Prepare AFP Rename File cleanup destination" \ "./afp_delete_smoke $COMMON_PRINT '$RENAME_FILE_TO_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_FILE_TO_PATH" || true run_cmd \ "AFP Rename File create source" \ "./afp_create_file_smoke $COMMON_PRINT '$RENAME_FILE_FROM_PATH'" \ "$SCRIPT_DIR/afp_create_file_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_FILE_FROM_PATH" run_cmd \ "AFP Rename File" \ "./afp_rename_smoke $COMMON_PRINT '$RENAME_FILE_FROM_PATH' '$RENAME_FILE_TO_PATH'" \ "$SCRIPT_DIR/afp_rename_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_FILE_FROM_PATH" "$RENAME_FILE_TO_PATH" run_cmd \ "AFP Rename File cleanup" \ "./afp_delete_smoke $COMMON_PRINT '$RENAME_FILE_TO_PATH'" \ "$SCRIPT_DIR/afp_delete_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$RENAME_FILE_TO_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 FinderInfo WebSDK layout" \ "./afp_set_file_info_smoke $COMMON_PRINT --websdk-layout --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" \ --websdk-layout --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH" run_cmd \ "AFP Set File Information FinderInfo WebSDK legacy" \ "./afp_set_file_info_smoke $COMMON_PRINT --afp09 --websdk-layout --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 --websdk-layout --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH" run_cmd \ "AFP Set File Information Hidden WebSDK layout" \ "./afp_set_file_info_smoke $COMMON_PRINT --websdk-layout --attributes-only --hidden '$NETWARE_PATH'" \ "$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \ --websdk-layout --attributes-only --hidden "$NETWARE_PATH" run_cmd \ "AFP Set File Information Clear Hidden WebSDK layout" \ "./afp_set_file_info_smoke $COMMON_PRINT --websdk-layout --attributes-only --clear-hidden '$NETWARE_PATH'" \ "$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \ --websdk-layout --attributes-only --clear-hidden "$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 Access Timestamp" \ "./afp_set_file_info_smoke $COMMON_PRINT --access-time-only --access-time-epoch '$TIMESTAMP_EPOCH' '$NETWARE_PATH'" \ "$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \ --access-time-only --access-time-epoch "$TIMESTAMP_EPOCH" "$NETWARE_PATH" run_cmd \ "AFP Set File Information Create Timestamp" \ "./afp_set_file_info_smoke $COMMON_PRINT --create-time-only --create-time-epoch '$TIMESTAMP_EPOCH' '$NETWARE_PATH'" \ "$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \ --create-time-only --create-time-epoch "$TIMESTAMP_EPOCH" "$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 Backup Timestamp" \ "./afp_set_file_info_smoke $COMMON_PRINT --backup-time-only --backup-time-epoch '$TIMESTAMP_EPOCH' '$NETWARE_PATH'" \ "$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \ --backup-time-only --backup-time-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 Get File Information readonly rights" \ "./afp_file_info_smoke --expect-rights-set 0x0100 --expect-rights-clear 0x9200 $READONLY_PRINT '$NETWARE_PATH'" \ "$SCRIPT_DIR/afp_file_info_smoke" --expect-rights-set 0x0100 --expect-rights-clear 0x9200 \ -S "$SERVER" -U "$READONLY_USER" "${READONLY_AUTH_ARGS[@]}" "$NETWARE_PATH" 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_optional_cmd \ "Linux xattr: AFP Attributes (optional AFP-only bits)" \ "getfattr -n user.org.mars-nwe.afp.attributes -e hex '$UNIX_PATH'" \ getfattr -n user.org.mars-nwe.afp.attributes -e hex "$UNIX_PATH" || \ emit "AFP-only attributes xattr is absent; this is expected when the tested Hidden/System/Archive bits are stored through the NetWare attribute path." run_cmd \ "Linux xattr: NetWare FileInfo metadata" \ "getfattr -n user.org.mars-nwe.netware.fileinfo -e hex '$UNIX_PATH'" \ getfattr -n user.org.mars-nwe.netware.fileinfo -e hex "$UNIX_PATH" run_cmd \ "Linux xattr: NetWare Archive metadata" \ "getfattr -n user.org.mars-nwe.netware.archive -e hex '$UNIX_PATH'" \ getfattr -n user.org.mars-nwe.netware.archive -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