Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!uwm.edu!genbank!apple!motcsd!xdos!doug From: doug@xdos.UUCP (Doug Merritt) Newsgroups: comp.sys.amiga.tech Subject: Re: Anybody know how to do this stuff? Summary: C code enclosed -- "fs.c" Message-ID: <584@xdos.UUCP> Date: 13 Dec 89 05:06:38 GMT References: <13920020@hpfelg.HP.COM> <13920027@hpfelg.HP.COM> <4730@sugar.hackercorp.com> Reply-To: doug@xdos.UUCP (Doug Merritt) Organization: Hunter Systems, Mountain View CA (Silicon Valley) Lines: 594 In article <4730@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: >In article <13920027@hpfelg.HP.COM> koren@hpfelg.HP.COM (Steve Koren) writes: >> I want to find out, for any given device name, whether that is a currently >> mounted file system device. > >There are two parts to this question. First, whether it's a file-system device. >Second, whether it's currently mounted. The second is easy... you can just >set your pr_windowptr to -1 and try to access it. To see if it's a file >system device is a bit harder. You can try doing a getdiskinfo on it. > >Or you can traverse the device list and kill two birds with one stone. Let >me dig up the code... > >Bummer. That disk has an error. I'll run disksalv on it while I read news and >let you know what comes out. (let's see you do *that* on a Mac!) Since I haven't seen Peter's code yet (DOA? Give my regards to Lazarus), here's mine ("fs.c"). Hmmm. I just saw Peter's code after all, but since I spent an hour creating "fs.c" out of the relevent piece of my "filetype" program, I'll post it anyway. It does lots more than Peter's code (weak justification for posting :-). In fact, it does more than you asked for...given a device/volume/assign name, it tells you everything known about it (see examples below). If you want to follow Peter's suggestion about having SKsh wildcard device names, I'm very much in favor...I'm always wishing the CLI supported that. Anyway, as I said in another posting today, my filetype program does exactly that, and I can give you complete working code to support that feature if you want it. As for this "fs.c", it works quite well, although I see Chuck McManis just posted something (Subject: "Re: Problem with handler) that suggests that in addition to checking for a handler task, I should perhaps also check DSKENV and even send an ACTION_DISKINFO packet. I'll have to look into that; but meanwhile the simple check has never produced any problem reports. Examples of 'fs' in action: For instance, "fs Workbench1.3:" produces Workbench1.3: -- volume (mounted on DF0) Conversely, "fs df0:" produces df0: -- device (file system; contains Workbench1.3) After ejecting the diskette, the same commands produces df0: -- device (file system; ejected) Or for ASSIGN'ed directories, "fs src:" produces src: -- directory (SupraDrive0:SOURCE) The code works on ram:, rad:, etc. Hope it helps. Doug -- Doug Merritt {pyramid,apple}!xdos!doug Member, Crusaders for a Better Tomorrow Professional Wildeyed Visionary ---------------------- CUT HERE ---------------------------------- /* * fs -- check filesystem devices (extracted from my 'filetype' source) * * copyright 1987 Douglas R. Merritt * License to use is hereby granted on the condition that this * notice be retained unchanged, and that any commercial * use must conspicuously credit the copyright holder. * */ #define NONE_SUCH 0 #define DEVICE 1 #define DIRECTORY 2 #define VOLUME 3 char *ExtraInfo; #define TextCountDirEntries(N) "" char *strdup(), *Name2Path(), *concat3(); #include "ctype.h" #include "exec/types.h" #include "libraries/dos.h" #ifdef BADDR #undef BADDR #endif #define BADDR(N) ((char *) ( ((ULONG)(N)) << 2) ) #define BCAST(TYPE, VAL) ((TYPE) BADDR((ULONG)VAL)) /* * RoundUp0 -- ceiling (yields 0 if n % TO == 0) * BufRound -- given buffer address, rounds up to word boundary */ #define RoundUp0(N,TO) ( (TO - (((ULONG)N) & (TO-1)) ) & (TO-1)) #define BufRound(BUF) &BUF[ RoundUp0(BUF,4) ] extern char *calloc(); extern struct FileHandle *Output(), *Open(), *output; extern ULONG Read(); #include "exec/nodes.h" #include "exec/memory.h" #include "exec/resident.h" #include "libraries/dosextens.h" #include "libraries/dos.h" #include "libraries/diskfont.h" #include "libraries/filehandler.h" #include "exec/libraries.h" #include "workbench/startup.h" ULONG Examine(), ExNext(); /* move to def.h? */ struct FileLock *Lock(), *ParentDir(); struct Process *FindTask(); struct FileInfoBlock *GetInfo(); char *FileName(), *Name2Path(), *concat3(); extern struct DosLibrary *DOSBase; typedef struct DeviceList *DevPtr; /************************* misc. functions ************************/ /* * is this a device name? (e.g. "ser:") */ int IsDevName(name) char *name; { char *s; for (s=name; *s; ++s) if (*s == ':') break; if (!s[0] || s[1]) return(0); return(1); } /* IsDevName() */ /* * compare a string and a BSTR, case-insensitive */ StrBstrCmp(s, b) unsigned char *s; BPTR b; { int total, rdone, sdone, c1, c2; unsigned char *r, *rstart; if (!s || !b) return(-1); r = (unsigned char *) BADDR(b); total = *r++; rstart = r; rdone = sdone = 0; while (1) { if (!*s) sdone = 1; if ((r - rstart) >= total) rdone = 1; if (sdone || rdone) return(sdone - rdone); c1 = isupper(*s) ? tolower(*s) : *s; c2 = isupper(*r) ? tolower(*r) : *r; if (c1 != c2) return(c1 - c2); ++s; ++r; } /*NOTREACHED*/ } /* StrBstrCmp() */ /* * convert a BSTR to a string * We count on exit() freeing the allocated memory. */ char * Bstr2Str(s) unsigned char *s; { char *ret; int len; if (!s) s = (unsigned char *) "\0"; else s = (unsigned char *) BADDR(s); len = s[0] & 0xff; ret = calloc(1, len+2); strncpy(ret, &s[1], len); ret[ len ] = '\0'; return(ret); } /* Bstr2Str() */ /* * given a pointer to the MsgPort part of a task structure, return * the name found in the Node portion. */ char * taskname(p) struct MsgPort *p; { struct Node *t; char *s; if (!p) return(0); t = (struct Node *) p->mp_SigTask; if (t->ln_Name) { s = t->ln_Name; if (*s) return(strdup(s)); } return((char *) 0); } /* taskname() */ /* * case-insensitive string compare */ stricmp(a, b) /*register*/ char *a, *b; { int c1, c2; if (!a || !b) return(-1); while (*a && *b) { c1 = isupper(*a) ? tolower(*a) : *a; c2 = isupper(*b) ? tolower(*b) : *b; if (c1 != c2) return(c1 - c2); ++a; ++b; } return(((int) *a) - ((int) *b)); } /* stricmp() */ #define GetLock(cur) BCAST(struct FileLock *, cur->dl_Lock) #define GetVol(cur) BCAST(struct DeviceList *, cur->fl_Volume) #define DevNode(cur) ((struct DeviceNode *) cur) #define IsVolMounted(cur) (cur->dl_Task != NULL) /* * Find device list entry of specified type and handler values. * Used to match volumes with devices & vice versa. */ struct DeviceList * FindDevType(task, type) struct MsgPort *task; ULONG type; { struct DosInfo *dos; struct RootNode *root; struct DeviceList *dev, *cur; if (!task) return(0); /* * find device list, starting from Dosbase; see AmyDos Tech. Ref Man * and libraries/dosextens.h */ root = (struct RootNode *) DOSBase->dl_Root; dos = BCAST(struct DosInfo *, root->rn_Info); dev = BCAST(struct DeviceList *, dos->di_DevInfo); /* device is *supposed* to be treated differently, so we do: */ if (type == DLT_DEVICE) { Forbid(); for (cur=dev; cur!=NULL; cur=BCAST(DevPtr, cur->dl_Next)) { if (cur->dl_Type != DLT_DEVICE) continue; if (DevNode(cur)->dn_Task == task) { Permit(); return(cur); } } Permit(); } else { Forbid(); for (cur=dev; cur!=NULL; cur=BCAST(DevPtr, cur->dl_Next)) { if (cur->dl_Type != type) continue; if (cur->dl_Task == task) { Permit(); return(cur); } } Permit(); } return(0); } /* FindDevType() */ /* * check device list to see if this name is on it */ int IsDevice(buf) char *buf; { struct DosInfo *dos; struct RootNode *root; struct MsgPort *task; DevPtr dev, cur; char *s, name[128], *strchr(); char *str, *on, *devname; enum FILETYPE ret; int mtd, isfs; struct Process *tp; APTR tmp; strcpy(name, buf); if (s=strchr(name, ':')) *s = '\0'; /* erase ':' */ else return(NONE_SUCH); /* fail safe...shouldn't happen */ /* * find device list, starting from Dosbase; see AmyDos Tech. Ref Man * and libraries/dosextens.h */ Forbid(); /* vvvvvv */ root = (struct RootNode *) DOSBase->dl_Root; dos = BCAST(struct DosInfo *, root->rn_Info); dev = BCAST(struct DeviceList *, dos->di_DevInfo); for (cur=dev; cur!=NULL; cur=BCAST(DevPtr, cur->dl_Next)) { s = BCAST(char *, cur->dl_Name); if (StrBstrCmp(name, cur->dl_Name)) continue; switch(cur->dl_Type) { case DLT_DEVICE: #if 0 /* * this older code is interesting, but it turns out nobody puts * anything very useful in those fields. */ if (DevNode(cur)->dn_Handler) { ExtraInfo = Bstr2Str(DevNode(cur)->dn_Handler); } else if (DevNode(cur)->dn_Task) { ExtraInfo = taskname(DevNode(cur)->dn_Task); } if (!ExtraInfo || !*ExtraInfo || !isprint(*ExtraInfo) || !isprint(ExtraInfo[1])) ExtraInfo = "no id"; #endif task = DevNode(cur)->dn_Task; Permit(); /* ^^^^^^ */ #if 0 tp = FindTask((char *) 0 ); tmp = tp->pr_WindowPtr; tp->pr_WindowPtr = (APTR) -1L; isfs = IsDir(GetInfo(buf)); tp->pr_WindowPtr = tmp; if (isfs) { #endif if (task) { char buf[256], *str; strcpy(buf, "file system; "); if (cur=FindDevType(task, DLT_VOLUME)) { str = Bstr2Str(cur->dl_Name); strcat(buf, "contains "); strcat(buf, str); free(str); } else { strcat(buf, "ejected"); } ExtraInfo = strdup(buf); } else { ExtraInfo = "non-file system"; } return(DEVICE); case DLT_DIRECTORY: cur = GetVol(GetLock(cur)); mtd = IsVolMounted(cur); Permit(); /* ^^^^^^ */ if (mtd) { ExtraInfo = Name2Path(buf); } else { char *tmp, *dup; dup = Bstr2Str(cur->dl_Name); tmp = "unmounted volume "; ExtraInfo = concat3(tmp, dup, ""); free(dup); } return(DIRECTORY); case DLT_VOLUME: mtd = IsVolMounted(cur); Permit(); /* ^^^^^^ */ if (!mtd) { ExtraInfo = "unmounted"; return(VOLUME); } /* * avoid bug in ram disk; try * dir "RAM Disk:" * (task hangs, don't say I didn't warn you) */ if (!stricmp(buf, "RAM Disk:")) { str = TextCountDirEntries("ram:"); } else { str = TextCountDirEntries(buf); } task = DevNode(cur)->dn_Task; /* "impossible" error: */ if (!(cur=FindDevType(task, DLT_DEVICE))) { devname = strdup("???"); } else { devname = Bstr2Str(cur->dl_Name); } on = "mounted on ", ExtraInfo = concat3(str, on, devname); free(str); free(devname); return(VOLUME); default: Permit(); /* ^^^^^^ */ ret = NONE_SUCH; return(ret); } break; } Permit(); /* ^^^^^^ */ return(NONE_SUCH); /* unknown volume name */ } /* IsDevice() */ /* * copy a string into newly allocated space */ char * strdup(s) char *s; { char *ret; if (!s) return(0); ret = calloc(1, strlen(s)+1); strcpy(ret, s); return(ret); } /* strdup() */ /* * concatenate 3 strings into newly allocated storage */ char * concat3(a, b, c) char *a, *b, *c; { int total; char *ret; register char *tmp; total = strlen(a) + strlen(b) + strlen(c); tmp = ret = calloc(1, total+1); while (*a) *tmp++ = *a++; while (*b) *tmp++ = *b++; while (*c) *tmp++ = *c++; *tmp = '\0'; return(ret); } /* concat3() */ /* * convert any name (e.g. relative to current directory) to its * true full path name (in newly allocated space) */ char * Name2Path(name) char *name; { struct FileLock *Ilock; char buf[256]; Ilock = Lock(name, (ULONG) ACCESS_READ); if (!Ilock) return(strdup(name)); Lock2Path(Ilock, buf); UnLock(Ilock); return(strdup(buf)); } /* Name2Path() */ /* * Get full path corresponding to lock (locked file should exist!) * Since we have to go upward one directory at a time, * we have to go all the way to the top before we can build * the path left to right. A data stack is used for this. */ Lock2Path(curlock, pathbuf) struct FileLock *curlock; char *pathbuf; { #define LOCKSTACKSIZE 128 struct FileLock *locklist[LOCKSTACKSIZE]; UBYTE Ibuf [ sizeof(struct FileInfoBlock) + 4]; struct FileInfoBlock *Ifib; int i; char *s, *path; Ifib = (struct FileInfoBlock *) BufRound(Ibuf); if (!Examine(curlock, Ifib)) return(0); /* if (!IsDir(Ifib)) return(0); */ /* * find full path name; build LIFO stack of * pushed locks; when full use popped locks with * Examine() to get each name in path. */ for (i=0; i= LOCKSTACKSIZE) { err("Too many subdirectories"); *path++ = '?'; *path++ = '/'; --i; } /* * concatenate each component of path */ if (!Examine(locklist[i--], Ifib)) goto wierd; for (s=Ifib->fib_FileName; *s; ) *path++ = *s++; *path++ = ':'; while (i >= 0) { if (!Examine(locklist[i], Ifib)) goto wierd; for (s=Ifib->fib_FileName; *s; ) *path++ = *s++; if (i>0) *path++ = '/'; --i; } *path = '\0'; return(path - &pathbuf[0]); wierd: *path++ = '?'; *path++ = '/'; *path = '\0'; return(path - &pathbuf[0]); } /* Lock2Path() */ /* * is this a directory? */ IsDir(Ifib) struct FileInfoBlock *Ifib; { if (!Ifib) return(0); if (Ifib->fib_DirEntryType > 0) return(1); return(0); } /* IsDir() */ main(argc, argv) int argc; char **argv; { int type; char *typename; if (argc != 2 || !IsDevName(argv[1])) { printf("Usage (e.g)-- devinfo df0:\n"); exit(1); } type = IsDevice(argv[1]); printf("%s -- ", argv[1]); switch(type) { case NONE_SUCH: typename = "does not exist"; break; case DEVICE: typename = "device"; break; case DIRECTORY: typename = "directory"; break; case VOLUME: typename = "volume"; break; default: typename = "???"; } printf(" %s ", typename); if (ExtraInfo) printf("(%s)\n", ExtraInfo); else printf("\n"); } err(s) char *s; { printf("error: %s\n", s); } -- Doug Merritt {pyramid,apple}!xdos!doug Member, Crusaders for a Better Tomorrow Professional Wildeyed Visionary