docs: split afp selector notes

This commit is contained in:
Mario Fetka
2026-06-02 19:25:46 +00:00
parent 916007b608
commit 800ca21aff
3 changed files with 352 additions and 134 deletions

25
AI.md
View File

@@ -1015,3 +1015,28 @@ Latest endpoint audit checkpoint from patch 0248:
unlisted gaps and ignoring 5.x-only endpoints.
Next patch number should be `0249`.
Latest endpoint audit checkpoint from patch 0249:
- Continued NDK-first after the TTS family with the in-scope AFP/Mac namespace
family `35/01` through `35/19` in `src/nwconn.c`. The NDK lists these AFP
calls for NetWare 2.x/3.x/4.x, so they remain relevant even though the same
pages also mention 5.x.
- Converted the AFP dispatcher from grouped `if`/`else` pairs into an explicit
`switch (ufunc)` with one case per NDK selector: create directory/file,
delete, entry-ID lookup by name/handle/path, rename, open file fork,
get/set/scan file information, AFP 2.0 create/get/set/scan variants, DOS-name
lookup, and deleted-file Macintosh-info lookup.
- Runtime behavior is unchanged. Some selectors still share the same helper,
but each selector now has its own case-local `Request:` and `Response:`
summary matching the endpoint-audit rule. Do not regroup these cases in a
later cleanup.
- Future AFP work must keep stable AFP entry IDs/CNIDs, FinderInfo/ProDOSInfo,
data/resource fork identity, directory enumeration state, and Salvage metadata
grounded in real provider state. Do not fake AFP replies from plain Unix path
names when the NDK requires namespace identity or metadata persistence.
- The next NDK-first pass should continue with the next documented NetWare
1.x/2.x/3.x endpoint or planned 4.x endpoint after the AFP family, skipping
unlisted gaps and ignoring 5.x-only endpoints.
Next patch number should be `0250`.

40
TODO.md
View File

@@ -1652,3 +1652,43 @@ Follow-up:
- Continue NDK-first with the next documented NetWare 1.x/2.x/3.x endpoint or
planned 4.x endpoint after the TTS family, keeping one case and
Request/Response comment per selector.
### AFP selector split 35/01..19
Current status:
- Patch `0249` audits the NDK-listed, NetWare-2.x/3.x/4.x-relevant AFP/Mac
namespace family `0x2222/35` in `src/nwconn.c`.
- The old grouped AFP `if`/`else` dispatcher has been converted to one explicit
`switch (ufunc)` case per selector, each with adjacent Request/Response notes:
- `35/01` AFP Create Directory
- `35/02` AFP Create File
- `35/03` AFP Delete
- `35/04` AFP Get Entry ID From Name
- `35/05` AFP Get File Information
- `35/06` AFP Get Entry ID From NetWare Handle
- `35/07` AFP Rename
- `35/08` AFP Open File Fork
- `35/09` AFP Set File Information
- `35/10` AFP Scan File Information
- `35/11` AFP Alloc Temporary Directory Handle
- `35/12` AFP Get Entry ID From Path Name
- `35/13` AFP 2.0 Create Directory
- `35/14` AFP 2.0 Create File
- `35/15` AFP 2.0 Get File Or Directory Information
- `35/16` AFP 2.0 Set File Information
- `35/17` AFP 2.0 Scan File Information
- `35/18` AFP Get DOS Name From Entry ID
- `35/19` AFP Get Macintosh Info On Deleted File
- Runtime behavior is unchanged; shared helpers remain shared, but no selector
is documented only through a grouped sibling case.
- Future AFP implementation work requires stable entry IDs/CNIDs, FinderInfo and
ProDOSInfo persistence, data/resource fork identity, directory enumeration
state, and Salvage metadata. Do not synthesize AFP success from partial Unix
path data alone.
Follow-up:
- Continue NDK-first with the next documented NetWare 1.x/2.x/3.x endpoint or
planned 4.x endpoint after the AFP family, keeping one case and
Request/Response comment per selector.

View File

@@ -6117,140 +6117,293 @@ static int handle_ncp_serv(void)
* missing-endpoint source stubs are needed for the current
* 1.x/2.x/3.x plus planned-4.x scope.
*/
if (ufunc == 0x01 || ufunc == 0x0d) {
/* 35/01 AFP Create Directory and 35/13 AFP 2.0 Create
* Directory. Request carries volume/base/path and
* creation metadata; reply has no extra payload.
* MARS-NWE routes both through the same path-backed
* directory creation helper. */
int result = afp_create_directory(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x02 || ufunc == 0x0e) {
/* 35/02 AFP Create File and 35/14 AFP 2.0 Create File.
* Request carries volume/base/path, attributes and AFP
* metadata fields; reply has no extra payload. Current
* compatibility path creates the data fork/file and AFP
* metadata through the shared helper. */
int result = afp_create_file(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x03) {
/* 35/03 AFP Delete. Request selects the AFP entry/path;
* reply has no payload. Current helper maps the AFP
* selector to the shared filesystem delete path. */
int result = afp_delete_object(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x07) {
/* 35/07 AFP Rename. Request carries source and target
* AFP path/name data; reply has no payload. */
int result = afp_rename_object(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x04) {
/* 35/04 AFP Get Entry ID From Name. Request supplies
* volume/base AFP ID and a modifying path string; reply
* returns AFP entry information. Until persistent CNID
* lookup exists this is the SYS:-style path-backed
* compatibility subset. */
int result = afp_get_entry_id_from_name(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x06) {
/* 35/06 AFP Get Entry ID From NetWare Handle. Request
* contains an open NetWare file handle; reply returns the
* corresponding AFP entry ID for the mapped Unix path. */
int result = afp_get_entry_id_from_netware_handle(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x08) {
/* 35/08 AFP Open File Fork. Request selects AFP entry
* and fork; reply returns a normal NetWare file handle.
* Current compatibility opens the data fork read-only for
* the path-backed subset. */
int result = afp_open_file_fork(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x0b) {
/* 35/11 AFP Alloc Temporary Directory Handle. Request
* carries AFP path selection; reply returns a temporary
* NetWare directory handle plus effective rights. */
int result = afp_alloc_temporary_dir_handle(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x0c) {
/* 35/12 AFP Get Entry ID From Path Name. Request uses a
* path-name selector; reply returns AFP entry ID data.
* SDK helpers use this as an AFP-support probe. */
int result = afp_get_entry_id_from_path_name(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x12) {
/* 35/18 AFP Get DOS Name From Entry ID. Request carries
* an AFP entry ID; reply returns the DOS/NetWare name. */
int result = afp_get_dos_name_from_entry_id(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x13) {
/* 35/19 AFP Get Macintosh Info On Deleted File. Request
* selects a deleted AFP entry; reply returns FinderInfo,
* ProDOSInfo, resource fork size, and deleted filename
* from the shared Salvage snapshot. */
int result = afp_get_macintosh_info_on_deleted_file(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x05 || ufunc == 0x0f) {
/* 35/05 AFP Get File Information and 35/15 AFP 2.0 Get
* File Or Directory Information. Request selects AFP
* entry/path; reply returns AFP metadata and filesystem
* information. Both use the same read-only helper until
* richer persistent entry-id lookup exists. */
int result = afp_get_file_information(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x09 || ufunc == 0x10) {
/* 35/09 AFP Set File Information and 35/16 AFP 2.0 Set
* File Information. Request carries AFP metadata update
* fields; reply has no payload. Current compatibility
* accepts FinderInfo plus metadata-only DOS attribute
* writes through the xattr-backed AFP metadata path. */
int result = afp_set_file_information(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x0a || ufunc == 0x11) {
/* 35/10 AFP Scan File Information and 35/17 AFP 2.0 Scan
* File Information. Request carries search sequence and
* AFP path/attribute filters; reply returns one scanned
* AFP file-information record in the conservative helper. */
int result = afp_scan_file_information(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else {
XDPRINTF((3,0,
"INFO AFP 35/%d UNKNOWN name=\"%s\" backend=\"%s\" fn=0x23 sub=0x%02x result=0xbf",
ufunc, afp_call_name(ufunc),
nwatalk_backend_available() ? "enabled" : "disabled",
ufunc));
completition=0xbf; /* we say invalid namespace here */
switch (ufunc) {
case 0x01: { /* SDK 35/01 AFP Create Directory */
/*
* Request: SubFunctionCode=1, byte VolumeNumber,
* long BaseDirectoryID, byte Reserved,
* byte FinderInfo[32], byte PathLen,
* byte PathModString[PathLen].
* Response: long NewDirectoryID. Requires an AFP
* namespace directory create with stable entry IDs.
*/
int result = afp_create_directory(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x02: { /* SDK 35/02 AFP Create File */
/*
* Request: SubFunctionCode=2, byte VolumeNumber,
* long BaseDirectoryID, byte DeleteExistingFileFlag,
* byte FinderInfo[32], byte PathLen,
* byte PathModString[PathLen].
* Response: long NewDirectoryID. Requires data-fork
* create plus AFP metadata persistence.
*/
int result = afp_create_file(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x03: { /* SDK 35/03 AFP Delete */
/*
* Request: SubFunctionCode=3, byte VolumeNumber,
* long BaseDirectoryID, byte PathLen,
* byte PathModString[PathLen].
* Response: no payload. Requires AFP namespace delete
* semantics for files and empty directories.
*/
int result = afp_delete_object(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x04: { /* SDK 35/04 AFP Get Entry ID From Name */
/*
* Request: SubFunctionCode=4, byte VolumeNumber,
* long MacBaseDirectoryID, byte PathStringLen,
* byte PathModString[PathStringLen].
* Response: long TargetEntryID. Requires stable AFP
* CNID/path lookup.
*/
int result = afp_get_entry_id_from_name(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x05: { /* SDK 35/05 AFP Get File Information */
/*
* Request: SubFunctionCode=5, byte VolumeNumber,
* long MacBaseDirectoryID, word RequestBitMap,
* byte PathStringLen,
* byte PathModString[PathStringLen].
* Response: AFP file/directory metadata selected by
* RequestBitMap. Requires AFP metadata plus filesystem
* stat information.
*/
int result = afp_get_file_information(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x06: { /* SDK 35/06 AFP Get Entry ID From NetWare Handle */
/*
* Request: SubFunctionCode=6,
* byte NetWareFileHandle[6].
* Response: byte VolumeID, long TargetEntryID,
* byte ForkIndicator. Requires open-handle to AFP
* namespace identity mapping.
*/
int result = afp_get_entry_id_from_netware_handle(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x07: { /* SDK 35/07 AFP Rename */
/*
* Request: SubFunctionCode=7, byte VolumeNumber,
* long SourceBaseDirectoryID, source path, long
* DestinationBaseDirectoryID, destination path.
* Response: no payload. Requires AFP namespace rename
* and metadata-preserving move semantics.
*/
int result = afp_rename_object(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x08: { /* SDK 35/08 AFP Open File Fork */
/*
* Request: SubFunctionCode=8, byte VolumeNumber,
* long MacBaseDirectoryID, byte ForkIndicator, access
* and path/fork selection fields.
* Response: byte NetWareFileHandle[6] plus open file
* metadata. Requires real AFP data/resource fork open.
*/
int result = afp_open_file_fork(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x09: { /* SDK 35/09 AFP Set File Information */
/*
* Request: SubFunctionCode=9, byte VolumeNumber,
* long MacBaseDirectoryID, word RequestBitMap,
* attributes, AFP dates/times, byte FinderInfo[32],
* byte PathStringLen,
* byte PathModString[PathStringLen].
* Response: no payload. Requires selected AFP metadata
* updates and compatible filesystem attribute writes.
*/
int result = afp_set_file_information(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x0a: { /* SDK 35/10 AFP Scan File Information */
/*
* Request: SubFunctionCode=10, sequence/search state,
* byte VolumeNumber, long MacBaseDirectoryID,
* RequestBitMap and path/filter fields.
* Response: one AFP scan result with file information
* fields. Requires stable AFP directory enumeration.
*/
int result = afp_scan_file_information(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x0b: { /* SDK 35/11 AFP Alloc Temporary Directory Handle */
/*
* Request: SubFunctionCode=11, byte VolumeNumber,
* long MacBaseDirectoryID, byte PathStringLen,
* byte PathModString[PathStringLen].
* Response: byte DirectoryHandle, byte AccessRights.
* Requires AFP path resolution to a NetWare temporary
* directory handle.
*/
int result = afp_alloc_temporary_dir_handle(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x0c: { /* SDK 35/12 AFP Get Entry ID From Path Name */
/*
* Request: SubFunctionCode=12, NetWare-style path
* selector and volume/path fields.
* Response: byte VolumeID, long TargetEntryID. Requires
* NetWare path to AFP entry-ID conversion.
*/
int result = afp_get_entry_id_from_path_name(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x0d: { /* SDK 35/13 AFP 2.0 Create Directory */
/*
* Request: SubFunctionCode=13 with AFP 2.0 directory
* create fields including volume/base/path and creation
* metadata.
* Response: long NewDirectoryID. Requires AFP 2.0
* namespace directory create semantics.
*/
int result = afp_create_directory(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x0e: { /* SDK 35/14 AFP 2.0 Create File */
/*
* Request: SubFunctionCode=14 with AFP 2.0 file create
* fields including volume/base/path, attributes and AFP
* metadata.
* Response: long NewDirectoryID. Requires data-fork
* create plus AFP 2.0 metadata persistence.
*/
int result = afp_create_file(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x0f: { /* SDK 35/15 AFP 2.0 Get File Or Directory Information */
/*
* Request: SubFunctionCode=15, AFP 2.0 volume/base/path
* selector and RequestBitMap.
* Response: AFP 2.0 file or directory information
* selected by RequestBitMap. Requires AFP metadata plus
* filesystem stat information.
*/
int result = afp_get_file_information(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x10: { /* SDK 35/16 AFP 2.0 Set File Information */
/*
* Request: SubFunctionCode=16, AFP 2.0 volume/base/path
* selector, RequestBitMap and metadata update fields.
* Response: no payload. Requires AFP 2.0 metadata and
* filesystem attribute update semantics.
*/
int result = afp_set_file_information(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x11: { /* SDK 35/17 AFP 2.0 Scan File Information */
/*
* Request: SubFunctionCode=17, AFP 2.0 scan sequence,
* volume/base/path and filter fields.
* Response: one AFP 2.0 scan result. Requires stable
* AFP directory enumeration and metadata projection.
*/
int result = afp_scan_file_information(afp_req,
afp_len, responsedata,
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x12: { /* SDK 35/18 AFP Get DOS Name From Entry ID */
/*
* Request: SubFunctionCode=18, byte VolumeNumber,
* long MacDirectoryEntryID.
* Response: byte PathStringLen,
* byte DOSPathString[PathStringLen]. Requires AFP
* entry-ID to NetWare/DOS path lookup.
*/
int result = afp_get_dos_name_from_entry_id(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
case 0x13: { /* SDK 35/19 AFP Get Macintosh Info On Deleted File */
/*
* Request: SubFunctionCode=19 and deleted-file AFP
* salvage selector fields.
* Response: FinderInfo, ProDOSInfo, resource fork size
* and deleted filename. Requires Salvage snapshot plus
* AFP metadata for deleted entries.
*/
int result = afp_get_macintosh_info_on_deleted_file(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} break;
default:
XDPRINTF((3,0,
"INFO AFP 35/%d UNKNOWN name=\"%s\" backend=\"%s\" fn=0x23 sub=0x%02x result=0xbf",
ufunc, afp_call_name(ufunc),
nwatalk_backend_available() ? "enabled" : "disabled",
ufunc));
completition=0xbf; /* we say invalid namespace here */
break;
}
} break;