/* DiskMisc.c - miscellaneous disk support routines. * Mark Rinfret (et al), 1987 * * History: (most recent change first) * * 12/15/87 -MRR- Added two new routines, FindDevice and GetVolumeName. * These are based largely on the "Info" program by * Chuck McManis. * * 11/24/87 -MRR- The routine "DiskBlocks" was changed to "DiskBlocksLeft". * A new routine, "TotalDiskBlocks", returns the capacity, * in disk blocks, of the drive associated with a pathname. * A new routine, "GetDiskInfo", returns InfoData on a given * pathname. */ #include #include #include #include #include #include #include #include #include #include #include #include ":src/lib/DiskMisc.h" extern LONG sendpkt(); static int errCode; extern struct DosLibrary *DOSBase; /* These are some macros that help in dealing with BCPL pointers and strings * the first is macro converts a BPTR to a C pointer of type struct DeviceList * * The second two provide the length of a BSTR * and a pointer to it's text. */ /* Convert BCPL DeviceList pointer to C pointer. */ #define DLPTR(x) ((struct DeviceList *)BADDR(x)) /* Get the length of a BCPL string. */ #define LENGTH(x) (unsigned) (*(UBYTE *)BADDR(x)) /* Get address of BCPL string, adjusted for leading length byte. */ #define STRING(x) (((char *)BADDR(x))+1) ^L /* * Find the first device node for a specified device type. * Called with: * dList: device list * dType: device type mnemonic * Returns: * pointer to device node or NULL * * Note: by passing the dl_Next field on successive calls, you may scan * the entire device list. */ struct DeviceList * FindDevice(dList, dType) struct DeviceList *dList; /* Pointer to a device list structure */ long dType; /* A device type as defined in dos.h */ { struct DeviceList *t; /* A temporary pointer */ for (t = dList; ((t != NULL) && (t->dl_Type != dType)); t = DLPTR(t->dl_Next)); return(t); } char * GetVolumeName(deviceName, volumeName) char *deviceName, *volumeName; { struct RootNode *rootNode; struct DeviceList *devList, *t, *t2; struct DeviceNode *devNode; struct DosInfo *dosInfo; char dName[31]; int i, nameLength; struct InfoData *info; struct Process *myProcess; APTR savedWindow; struct Lock *l; char *vName = NULL; /* set non-null on success */ *volumeName = '\0'; /* initialize name to null */ /* Make a copy of the device name string. */ strncpy(dName, deviceName, sizeof(dName)-1); /* Make sure that the device name is not colon-terminated. Also * insure that the device name is all upper case. */ nameLength = strlen(dName); for (i = 0; i < nameLength; ++i) { if (dName[i] == ':') { dName[i] = '\0'; break; } else dName[i] = toupper(dName[i]); } nameLength = strlen(dName); /* Get device name length. */ if (! (info = (struct InfoData *) AllocMem((long) sizeof(struct InfoData), MEMF_PUBLIC|MEMF_CLEAR))) { return vName; /* Will be NULL if unsuccessful. */ } /* Get the DOS root node. */ rootNode = (struct RootNode *)DOSBase->dl_Root; /* Get the DOS info node. */ dosInfo = (struct DosInfo *)BADDR(rootNode->rn_Info); /* devList becomes the anchor point that we always start from */ devList = (struct DeviceList *)BADDR(dosInfo->di_DevInfo); /* Disable requesters if no disk present */ myProcess = (struct Process *) FindTask(NULL); savedWindow = myProcess->pr_WindowPtr; myProcess->pr_WindowPtr = (APTR) -1L; for (t = FindDevice(DLPTR(dosInfo->di_DevInfo), DLT_DEVICE); t != NULL; t = FindDevice(DLPTR(t->dl_Next), DLT_DEVICE)) { devNode = (struct DeviceNode *) t; /* A non-null task pointer indicates a disk device. */ if (devNode->dn_Task) { #ifdef DEBUG char tempString[31]; strncpy(tempString, STRING(devNode->dn_Name), LENGTH(devNode->dn_Name) ); printf("Testing %s\n", tempString); #endif if (!strncmp(dName, STRING(devNode->dn_Name), MAX(LENGTH(devNode->dn_Name),nameLength) ) ) { /* We've found a match! Now, add a terminating colon to the * device name so we can pass it to Lock. */ dName[nameLength++] = ':'; dName[nameLength] = '\0'; #ifdef DEBUG printf("Matched %s\n", deviceName); #endif l = (struct Lock *) Lock(dName, ACCESS_READ); if (l) { /* disk inserted? */ Info(l, info); t2 = DLPTR(info->id_VolumeNode); if (t2 != NULL) { strncpy(volumeName, STRING(t2->dl_Name), LENGTH(t2->dl_Name) ); volumeName[LENGTH(t2->dl_Name)] = '\0'; } #ifdef DEBUG else DebugWrite("Null volume name!\n"); #endif UnLock(l); } #ifdef DEBUG else printf("Unable to lock %s!\n", dName); #endif vName = volumeName; /* set 'success' */ break; } } /* end of disk device test */ } /* end for */ myProcess->pr_WindowPtr = savedWindow; /* restore window pointer */ cleanup: if (info) FreeMem(info, (long) sizeof(struct InfoData)); return vName; } /* This routine returns the number of disk blocks remaining on the * drive specified by 'name'. Though 'name' would typically be the * drive name or volume name, it can also be the name of any file * on the disk drive. * Called with: * name: disk device or volume name * Returns: * > 0 => number of blocks available * < 0 => error status */ LONG DiskBlocksLeft(name) char *name; { LONG blocks = -1L; struct InfoData *info = NULL; if ( !( info = GetDiskInfo(name) ) ) return -errCode; blocks = info->id_NumBlocks - info->id_NumBlocksUsed; FreeMem(info, (long) sizeof(struct InfoData)); return blocks; /* bad status indicator */ } /* Get disk info, given a pathname. * Called with: * name: file pathname * Returns: * a pointer to an InfoData structure * Note: * It is the user application's responsibility to free the memory * allocated for the InfoData structure. */ struct InfoData * GetDiskInfo( name ) char *name; { struct InfoData *info = NULL; struct FileLock *lock = NULL; errCode = 0; if (lock = (struct FileLock *) Lock(name, ACCESS_READ)) { if (info = AllocMem((long)sizeof(struct InfoData),MEMF_PUBLIC)) { if ( ! Info(lock,info)) errCode = IoErr(); } else errCode = ERROR_NO_FREE_STORE; UnLock(lock); } else errCode = IoErr(); if (errCode) { if (info) FreeMem( info, (long) sizeof( struct InfoData ) ); info = NULL; } return info; } /* Disk ACTION_INHIBIT support routine. * Author: Mark R. Rinfret * Date: 06/29/87 * * This routine provides support for user-written disk formatting, copy * operations which benefit from suppressing/restoring disk validation. */ int Inhibit(drivename, code) char *drivename; int code; { struct MsgPort *task; LONG arg[2]; LONG rc; if (!(task=(struct MsgPort *) DeviceProc(drivename))) return 1; /* fail, darn it! */ arg[0] = code; /* Now, cross all your fingers and toes... */ return ( !sendpkt(task,ACTION_INHIBIT,arg,1)); } /* This routine returns the total number of disk blocks on the * drive specified by 'name'. Though 'name' would typically be the * drive name or volume name, it can also be the name of any file * on the disk drive. * Called with: * name: disk device, volume or path name * Returns: * > 0 => total number of blocks on drive * < 0 => error status */ LONG TotalDiskBlocks(name) char *name; { struct InfoData *info = NULL; long int blocks = -1L; if ( ! ( info = GetDiskInfo(name) ) ) return -errCode; blocks = info->id_NumBlocks; FreeMem(info, (long) sizeof(struct InfoData)); return blocks; /* bad status indicator */ } #ifdef DEBUG main() { long blocks; char deviceName[81], volumeName[81]; if ((blocks = TotalDiskBlocks("df0:")) < 0) { printf("Bad status from TotalDiskBlocks() => %ld\n", -blocks); exit(); } else printf("Total disk blocks on DF0: => %ld\n", blocks); if ( (blocks = DiskBlocksLeft("df0:") ) < 0) printf("Bad status from DiskBlocks() => %ld\n", -blocks); else printf("Disk blocks left on df0: => %ld\n",blocks); for (;;) { puts("Enter a disk DEVICE name (dh0, df0, etc.)."); puts("Just hit RETURN to quit."); gets(deviceName); if (*deviceName == '\0') break; if (!GetVolumeName(deviceName, volumeName)) puts("Sorry - I couldn't find that device in my system."); else printf("The volume name is %s\n",volumeName); } } #endif