From f78ae0fb2a3f9b9a58b52dce858d9513bdcd3f6c Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Fri, 29 May 2026 23:34:55 +0200 Subject: [PATCH] nwconn: implement Get Extended Volume Information Wire NCP 0x16/0x33 Get Extended Volume Information to a real reply instead of returning 0xfb. The WebSDK documents NCP 0x2222/22/51 as taking a VolumeNumber and returning a low-high VolInfoReplyLen, an NWVolExtendedInfo structure, and a length-prefixed volume name. The SDK headers define NWVolExtendedInfo as 33 32-bit fields covering volume type, status flags, sector and cluster geometry, free-space counters, suballocation/limbo/compression/migration counters, directory counters, EA counters, a Directory Services object id, and a last-modified timestamp. Map the Unix filesystem data already used by the older volume-information calls to the core extended-volume fields: report a NetWare 386 v3.1 style volume type, 512-byte sectors, 8 sectors per cluster, total/free clusters, and directory-entry counters derived from fs_usage. Report NetWare-specific suballocation, limbo, compression, migration, EA, Directory Services, and timestamp fields as zero for now. Add the SDK request/reply semantics to the inline endpoint comment and remove the corresponding TODO entry. This enables the documented endpoint path while keeping the mapping conservative; fields MARS-NWE cannot currently model remain zero rather than guessed. --- TODO.md | 2 - src/nwconn.c | 106 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/TODO.md b/TODO.md index 9ba4685..ba875e3 100644 --- a/TODO.md +++ b/TODO.md @@ -68,8 +68,6 @@ Follow-up: - `NCP 0x16/0x18 Restore Directory Handle`: verify the exact SDK request/reply layout, then implement the documented function 22 / subfunction 24 directory-handle semantics. - - `NCP 0x16/0x33 Get Extended Volume Information`: return the documented - extended `VolumeInfo` structure and volume name instead of `0xfb`. - Keep SDK details close to the corresponding endpoint in `nwconn.c`, and keep broader prioritization/status here in `TODO.md`. diff --git a/src/nwconn.c b/src/nwconn.c index f81a260..4f57901 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -1646,27 +1646,97 @@ static int handle_ncp_serv(void) case 0x33 : { /* Get Extended Volume Information */ /* - * TODO(ncp-compat): Implement NCP 0x16/0x33 - * Get Extended Volume Information. + * NCP 0x2222/22/51 Get Extended Volume Information * - * SDK context: function 22 (0x16), subfunction 51 (0x33) takes - * a VolumeNumber and returns VolInfoReplyLen, a VolumeInfo - * structure, and the volume name. The documented VolumeInfo - * structure contains fields such as VolumeType, StatusFlagBits, - * SectorSize, SectorsPerCluster, VolumeSizeInClusters, - * FreedClusters, directory-entry counters, EA counters, a - * DirectoryServicesObjectID, and VolumeLastModifiedDateAndTime. + * WebSDK / nwvol.h context: + * Request: + * byte VolumeNumber + * Reply: + * word VolInfoReplyLen (Lo-Hi) + * NWVolExtendedInfo VolumeInfo (VolInfoReplyLen bytes) + * byte VolNameLen + * byte VolumeName[VolNameLen] * - * The existing older volume-info calls return only the small - * NetWare 2.x/3.x style subset, so filling this reply needs a - * deliberate mapping from Unix filesystem data to the extended - * SDK structure. + * NWVolExtendedInfo contains 33 little-endian 32-bit fields: + * volume type, status flags, sector/cluster geometry, total and + * free cluster counts, suballocation/limbo/compression/migration + * counters, directory-entry counters, EA counters, a Directory + * Services object id, and the last-modified date/time. + * + * MARS-NWE maps the Unix filesystem data we already expose via + * the older volume-information calls to the core geometry and + * capacity fields. NetWare-specific suballocation, limbo, + * compression, migration, EA, and DS fields are reported as zero. */ -#if 0 - int volume = (int) *(p+1); - /* next 3 byte are low bytes of volume */ -#endif - completition = 0xfb; /* not known yet */ + struct XDATA { + uint8 vol_info_reply_len[2]; + uint8 vol_type[4]; + uint8 status_flag[4]; + uint8 sector_size[4]; + uint8 sectors_per_cluster[4]; + uint8 vol_size_in_clusters[4]; + uint8 free_clusters[4]; + uint8 sub_alloc_freeable_clusters[4]; + uint8 freeable_limbo_sectors[4]; + uint8 nonfreeable_limbo_sectors[4]; + uint8 avail_sub_alloc_sectors[4]; + uint8 nonuseable_sub_alloc_sectors[4]; + uint8 sub_alloc_clusters[4]; + uint8 num_data_streams[4]; + uint8 num_limbo_data_streams[4]; + uint8 oldest_del_file_age_in_ticks[4]; + uint8 num_compressed_data_streams[4]; + uint8 num_compressed_limbo_data_streams[4]; + uint8 num_noncompressible_data_streams[4]; + uint8 precompressed_sectors[4]; + uint8 compressed_sectors[4]; + uint8 num_migrated_data_streams[4]; + uint8 migrated_sectors[4]; + uint8 clusters_used_by_fat[4]; + uint8 clusters_used_by_dirs[4]; + uint8 clusters_used_by_ext_dirs[4]; + uint8 total_dir_entries[4]; + uint8 unused_dir_entries[4]; + uint8 total_ext_dir_extants[4]; + uint8 unused_ext_dir_extants[4]; + uint8 ext_attrs_defined[4]; + uint8 ext_attr_extants_used[4]; + uint8 directory_services_object_id[4]; + uint8 vol_last_modified_date_and_time[4]; + uint8 vol_name_len; + uint8 vol_name[16]; + } *xdata = (struct XDATA*) responsedata; + uint8 name[100]; + int volume = (int) *(p+1); + int result = nw_get_volume_name(volume, name, sizeof(name)); + + memset(xdata, 0, sizeof(struct XDATA)); + if (result > -1) { + struct fs_usage fsp; + int namlen = strlen((char*)name); + + if (namlen > 16) namlen = 16; + U16_TO_16(33 * 4, xdata->vol_info_reply_len); + U32_TO_32(3, xdata->vol_type); /* VINetWare386v31 */ + U32_TO_32(512, xdata->sector_size); + U32_TO_32(8, xdata->sectors_per_cluster); /* 4 KiB clusters */ + + if (!nw_get_fs_usage(name, &fsp, 0)) { + U32_TO_32(fsp.fsu_blocks/8, xdata->vol_size_in_clusters); + U32_TO_32(fsp.fsu_bavail/8, xdata->free_clusters); + U32_TO_32(fsp.fsu_files, xdata->total_dir_entries); + U32_TO_32(fsp.fsu_ffree, xdata->unused_dir_entries); + } + + xdata->vol_name_len = namlen; + strmaxcpy(xdata->vol_name, name, namlen); + data_len = 2 + (33 * 4) + 1 + namlen; + XDPRINTF((5,0, + "NCP22/33 GetExtendedVolumeInfo: vol=%d name=`%s` len=%d", + volume, name, data_len)); + } else { + completition = (uint8) -result; + } } break;