How can I determine whether a volume is...
Articles and Tips: qna
01 Feb 2003
Q.
How can I determine whether a volume is an NSS (Novell Storage Systems) from a client workstation? I found a couple of LibC functions using the volume_info structure, which contains a flags field that has a bit set for an NSS volume, but nothing callable from the client.
A.
Here are three (count 'em, 3!) ways:
On NetWare 6, all NSS volumes have a subdirectory with the same name as the volume in the _ADMIN:\Manage_NSS\Volume directory. The directory should contain files called ModifiedFilesList.xml and VolumeInfo.xml.
So, for example, to determine if volume VOL1: is a NSS volume just attempt to open _ADMIN:\Manage_NSS\Volume\VOL1\VolumeInfo.xml. If the open succeeds, then the volume is NSS hosted.
Use NWGetExtendedVolumeInfo, as shown in the program below:
#include <nwdsapi.h> #include <nwdsconn.h> #include <nwvol.h> #include <stdio.h> #include <stdlib.h>
int main( int argc, char* argv[]) { NWDSCCODE dsccode; NWDSContextHandle context; NWCCODE ccode; NWCONN_HANDLE conn_handle; nuint16 volNum; NWVolExtendedInfo volInfo; if ( argc != 3) { puts( "Usage: ExtVInfo <server name> <volume name>"); return EXIT_FAILURE; } dsccode = NWDSCreateContextHandle(&context); if ( dsccode != 0) { printf("NWDSCreateContextHandle failed, dsccode = %x", dsccode); return EXIT_FAILURE; } ccode = NWDSLoginAsServer( context); if ( ccode != 0) { printf( "NWDSLoginAsServer failed, ccode = %x", ccode); NWDSFreeContext( context); return EXIT_FAILURE; } dsccode = NWDSOpenConnToNDSServer(context, argv[ 1], &conn_handle); if ( dsccode != 0) { printf( "NWDSOpenConnToNDSServerfailed, dsccode = %x", dsccode); NWDSFreeContext( context); return EXIT_FAILURE; } dsccode = NWDSAuthenticateConn(context, conn_handle); if ( dsccode != 0) { printf( "NWDSAuthenticateConn failed, dsccode = %x", dsccode); NWDSFreeContext( context); return EXIT_FAILURE; } ccode = NWGetVolumeNumber(conn_handle, argv[ 2], &volNum); if ( ccode != 0) { printf( "NWGetVolumeNumber failed,ccode = %x", ccode); NWDSFreeContext( context); return EXIT_FAILURE; } ccode = NWGetExtendedVolumeInfo( conn_handle, volNum, &volInfo); if ( ccode != 0) { printf( "NWGetExtendedVolumeInfo failed, ccode = %x", ccode); NWDSFreeContext( context); return EXIT_FAILURE; } printf( "%s: %s", argv[ 2], volInfo.statusFlag & NWCompressionEnabledBit ? "compression enabled" : "compression NOT enabled"); printf( ", %s\n", volInfo.statusFlag & 0x80000000 ? "NSS" : "traditional"); printf( "sectorSize : %lu\n", volInfo.sectorSize); printf( "freeableLimboSectors : %lu\n", volInfo.freeableLimboSectors); printf( "nonfreeableLimboSectors : %lu\n", volInfo.nonfreeableLimboSectors); NWDSFreeContext( context); return EXIT_SUCCESS; }
Assemble and send an NCP packet:
#include <errno.h> #include <nit/nwdir.h> #include <nwconn.h> #include <nwerrno.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
int main( int argc, char* argv[]) { int volumeNumber; #include <npackon.h> // don't move this directive to a different location struct GetVolumeInformationLevel1RequestPacket { unsigned short SubFuncStrucLen; unsigned char SubFuncCode; unsigned long VolumeNumber; unsigned long InfoLevelNumber; } req; struct GetVolumeInformationLevel1ReplyPacket { unsigned long CurrentServerTime; unsigned char VConsoleVersion; unsigned char VConsoleRevision; unsigned short reserved; unsigned long InfoLevel; // VolInfoDef: unsigned long VolumeType; unsigned long StatusFlagBits; unsigned long SectorSize; unsigned long SectorsPerCluster; unsigned long VolumeSizeInClusters; unsigned long FreedClusters; unsigned long SubAllocFreeableClusters; unsigned long FreeableLimboSectors; unsigned long NonFreeableLimboSectors; unsigned long NonFreeableAvailableSubAllocSectors; unsigned long NonUsableSubAllocSectors; unsigned long SubAllocClusters; unsigned long DataStreamsCount; unsigned long LimboDataStreamsCount; unsigned long OldestDeletedFileAgeInTicks; unsigned long CompressedDataStreamsCount; unsigned long CompressedLimboDataStreamsCount; unsigned long UnCompressedDataStreamsCount; unsigned long PreCompressedSectors; unsigned long CompressedSectors; unsigned long MigratedFiles; unsigned long MigratedSectors; unsigned long ClustersUsedByFAT; unsigned long ClustersUsedByDirectories; unsigned long ClustersUsedByExtendedDirectories; unsigned long TotalDirectoryEntries; unsigned long UnusedDirectoryEntries; unsigned long TotalExtendedDirectoryExtants; unsigned long UnUsedExtendedDirectoryExtants; unsigned long ExtendedAttributesDefined; unsigned long ExtendedAttributeExtantsUsed; unsigned long DirectoryServicesObjectID; unsigned long VolumeLastModifiedDateAndTime; } rep;
#include <npackoff.h> // don't move this directive to a different location int ccode; if ( argc != 2) { printf( "Usage: %s <vol_name>\n", argv[ 0]); return EXIT_FAILURE; } if ( GetVolumeNumber( argv[ 1], &volumeNumber) != 0) { printf( "GetVolumeNumber failed, errno = %d (%s), NetWareErrno = %d\n", errno, strerror( errno), NetWareErrno); return EXIT_FAILURE; } printf( "volumeNumber = %d\n", volumeNumber); req.SubFuncStrucLen = 0x900; // Hi-Lo req.SubFuncCode = 34; req.VolumeNumber = volumeNumber; req.InfoLevelNumber = 1; ccode = NWNCPSend( 123, &req, sizeof( req), &rep, sizeof( rep)); if ( ccode != ESUCCESS) { printf( "NWNCPSend failed, ccode = %d\n", ccode); return EXIT_FAILURE; } puts( rep.StatusFlagBits & 2 ? "compression enabled" : "compression not enabled"); puts( rep.StatusFlagBits & 0x80000000 ? "NSS" : "traditional"); return EXIT_SUCCESS; }
* Originally published in Novell AppNotes
Disclaimer
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.