;/*- dcc -r -ms -proto -new -v mountshare.c -o mountshare quit * ^^ This is PURE code! */ /*- * $Id$ * $Log$ * * SHARE.C * * This code is (C) Copyright 1992 by Olaf Seibert. All rights reserved. * May not be used or copied without a licence. -*/ #include #include #include #include #ifndef EXEC_TYPES_H #include #endif #ifndef EXEC_MEMORY_H #include #endif #ifndef LIBRARIES_DOSEXTENS_H #include #endif #ifndef LIBRARIES_FILEHANDLER_H #include #endif #ifndef RESOURCES_FILESYSRES_H #include #endif extern struct DosLibrary *DOSBase; typedef void *(*fptr) (long *, void *); struct DosInfo *DosInfo; struct FileSysResource *FileSysResource; char CreateFileSysEntry, TryLoadHandler, TryHandlerNames = 1, TryDosType = 1, TryFileSysEntry; #define nodb(x) x #define db(x) /* x */ void printbstr(BPTR bstr) { char *str = BADDR(bstr); if (bstr) fwrite(str + 1, str[0], 1, stdout); else printf(""); } void * traverse_bcpl(fptr function, BPTR start, void *context) { db(printf("traverse_bcpl: %x -> ", start);) start = BADDR(start); db(printf("%x\n", start);) while (start && (context = function((long *) start, context))) { start = BADDR(((long *) start)[0]); db(printf("traverse_bcpl: next is %x\n", start);) } return context; } struct c1 { char *name; struct DeviceNode *dn; }; void * compare_name(long *node, void *context) { struct c1 *c1 = (struct c1 *) context; struct DeviceNode *dnv = (struct DeviceNode *) node; char *dnvname = BADDR(dnv->dn_Name); db(printf("compare_name: "); printbstr(dnv->dn_Name); printf("\n");) if (dnv->dn_Type == DLT_DEVICE && dnvname[0] == strlen(c1->name) && strnicmp(c1->name, &dnvname[1], dnvname[0]) == 0) { c1->dn = dnv; db(printf("Type %ld Stack %ld Pri %ld Start %lx SegList %lx Task %lx GV %ld\n", dnv->dn_Type, dnv->dn_StackSize, dnv->dn_Priority, dnv->dn_Startup, dnv->dn_SegList, dnv->dn_Task, dnv->dn_GlobalVec);) return NULL; } return context; } struct DeviceNode * find_name(char *name) { struct c1 dn; dn.name = name; dn.dn = NULL; traverse_bcpl(compare_name, DosInfo->di_DevInfo, &dn); return dn.dn; } void load_handler(struct DeviceNode *dn) { char name[256]; char *handler; if (!TryLoadHandler) return; nodb(if (dn->dn_SegList != 0) { printf("Handler already loaded!\n"); return; }) nodb(if (dn->dn_Task != 0) { printf("Handler already running!\n"); return; }) handler = BADDR(dn->dn_Handler); if (handler == 0) { printf("Device has no Handler file\n"); return; } strncpy(name, handler + 1, *handler); name[*handler] = '\0'; dn->dn_SegList = LoadSeg(name); if (dn->dn_SegList) { printf("%s loaded.\n", name); } else { printf("Loading %s failed: error %ld.\n", name, IoErr()); } } /* * Try to get the DosType values from the mountlist. This is quite a * work! * We must be reasonable sure that the dn_Startup fields both refer * to a FileSysStarupMsg. They must both be pointers (and not some * small integral values, as used to distinguish CON and RAW, for * example). We also assume that fssm_Unit values <= 0xFFFF. */ unsigned long get_dostype(struct DeviceNode *dn) { struct FileSysStartupMsg *dnmsg; dnmsg = BADDR(dn->dn_Startup); if (dnmsg && (long)dnmsg > 100 && dnmsg->fssm_Unit <= 0x0000FFFF ) { long *dnenv = BADDR(dnmsg->fssm_Environ); /* actually struct DosEnvec */ if (dnenv && dnenv[0] >= DE_DOSTYPE) return dnenv[DE_DOSTYPE]; } #define NODOSTYPE ID_NO_DISK_PRESENT return NODOSTYPE; } int find_filesysentry(unsigned long dostype, struct DeviceNode *dn) { if (TryFileSysEntry && FileSysResource) { struct FileSysEntry *fse, *next; for (fse = FileSysResource->fsr_FileSysEntries.lh_Head; next = fse->fse_Node.ln_Succ; fse = next) { db(printf("Name %lx %s DosType %lx Version %lx SegList %lx\n", fse->fse_Node.ln_Name, fse->fse_Node.ln_Name, fse->fse_DosType, fse->fse_Version, fse->fse_SegList);) if (fse->fse_DosType == dostype) { /* * Patch the data from the FileSysEntry into the * DeviceNode. */ if (dn) { long *dnl = (long *)&dn->dn_Type; long *fsel = (long *)&fse->fse_Type; unsigned long patchflags = fse->fse_PatchFlags; while (patchflags) { if (patchflags & 1) { nodb(*dnl = *fsel;) } dnl++; fsel++; patchflags >>= 1; } } return 1; /* We found it */ } } } return 0; /* Didn't find anything */ } void make_filesysentry(struct DeviceNode *master) { unsigned long dostype; if (!CreateFileSysEntry) { return; } dostype = get_dostype(master); if (dostype != NODOSTYPE && find_filesysentry(dostype, NULL) == 0) { /* * So, there is no appropriate FileSysEntry for this DosType. * Let's create one! */ if (FileSysResource == NULL) { FileSysResource = AllocMem(sizeof(struct FileSysResource), MEMF_PUBLIC | MEMF_CLEAR); if (FileSysResource) { NewList(&FileSysResource->fsr_FileSysEntries); AddResource(FileSysResource); } } if (FileSysResource) { struct FileSysEntry *fse; fse = AllocMem(sizeof(*fse), MEMF_PUBLIC | MEMF_CLEAR); if (fse) { fse->fse_DosType = dostype; fse->fse_SegList = master->dn_SegList; #define patchbit(x) ((offsetof(struct FileSysEntry, x) - \ offsetof(struct FileSysEntry, fse_Type)) / sizeof(long)) fse->fse_PatchFlags |= 1 << patchbit(fse_SegList); AddTail(&FileSysResource->fsr_FileSysEntries, &fse->fse_Node); } } } } struct c2 { struct DeviceNode *master; }; void * change(long *node, void *context) { struct c2 *c2 = (struct c2 *) context; struct DeviceNode *dnv = (struct DeviceNode *) node; struct DeviceNode *master = c2->master; unsigned long dnvDosType; db(printf("change: "); printbstr(dnv->dn_Name); printf("\n");) if (dnv->dn_Type != DLT_DEVICE || dnv->dn_Type != master->dn_Type) { db(printf("Not a device\n");) return context; /* keep looking */ } nodb(if (dnv->dn_SegList != 0) { db(printf("Device has SegList\n");) return context; /* keep looking */ }) nodb(if (dnv->dn_Task != 0) { db(printf("Device has Task\n");) return context; /* keep looking */ }) /* * See if both have the same handler filename. */ if (TryHandlerNames) { char *dnvhandler = BADDR(dnv->dn_Handler); char *masterhandler = BADDR(master->dn_Handler); db(printf("Handlers: '"); printbstr(dnv->dn_Handler); printf("' - '"); printbstr(master->dn_Handler); printf("'\n");) if (dnvhandler && masterhandler) { if (strnicmp(&dnvhandler[0], &masterhandler[0], masterhandler[0]) == 0) { if (dnv->dn_SegList == 0) { dnv->dn_SegList = master->dn_SegList; /* Inform the user what happened */ printbstr(master->dn_Name); printf(" and "); printbstr(dnv->dn_Name); printf(" share handler "); printbstr(dnv->dn_Handler); printf(": SegList copied.\n"); goto done; } } } } /* * Try if the DosType values from the mountlist match. */ dnvDosType = get_dostype(dnv); if (TryDosType) { if (dnvDosType != NODOSTYPE && dnvDosType == get_dostype(master)) { db(printf("Dostypes %08x match!\n", dnvDosType);) if (dnv->dn_SegList == 0) { nodb(dnv->dn_SegList = master->dn_SegList;) /* Inform the user what happened */ printbstr(master->dn_Name); printf(" and "); printbstr(dnv->dn_Name); printf(" have the same DosType (0x%08lx): SegList copied\n", dnvDosType); goto done; } } } /* * Try to find a FileSysResource with this DosType. */ if (TryFileSysEntry && dnvDosType != NODOSTYPE) { if (find_filesysentry(dnvDosType, dnv)) { /* Inform the user what happened */ printf("There is a FileSysEntry with DosType 0x%08lx: " "DeviceNode of ", dnvDosType); printbstr(dnv->dn_Name); printf(" patched.\n"); goto done; } } done: return context; } void spread(struct DeviceNode * master) { struct c2 dn; dn.master = master; traverse_bcpl(change, DosInfo->di_DevInfo, &dn); } void find_devlist(void) { struct RootNode *rn = (struct RootNode *) DOSBase->dl_Root; DosInfo = (struct DosInfo *) BADDR(rn->rn_Info); } void find_filesysr(void) { FileSysResource = OpenResource(FSRNAME); } void usage(void) { printf("usage: MountShare {{[+-][lchdf]} {}}\n" " +l: load Handler/FileSystem file\n" " +c: create FileSysEntry\n" " -h: don't compare Handler/FileSystem filenames\n" " -d: don't compare DosType values\n" " +f: search FileSysEntries\n" "The option opposite to default is shown.\n"); exit(10); } int main(int argc, char **argv) { int ac; char **av; ac = argc - 1; av = argv + 1; if (ac < 1) usage(); find_devlist(); find_filesysr(); while (ac > 0) { if (av[0][0] == '-' || av[0][0] == '+') { int val = av[0][0] == '+'; switch (av[0][1]) { case 'l': TryLoadHandler = val; break; case 'c': CreateFileSysEntry = val; break; case 'h': TryHandlerNames = val; break; case 'd': TryDosType = val; break; case 'f': TryFileSysEntry = val; break; default: usage(); } } else { struct DeviceNode *master; master = find_name(av[0]); if (master) { load_handler(master); make_filesysentry(master); spread(master); } else { printf("No device %s found.\n", av[0]); } } ac--; av++; } }