nwconn: implement Get Extended Volume Information
All checks were successful
Source release / source-package (push) Successful in 48s

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.
This commit is contained in:
Mario Fetka
2026-05-29 23:34:55 +02:00
parent bcf58e3b0a
commit f78ae0fb2a
2 changed files with 88 additions and 20 deletions

View File

@@ -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;