cmcmanis%pepper@Sun.COM (Chuck McManis) (03/15/88)
Greetings, generally when you pop out a disk the icon on the workbench disappears. Sometimes it doesn't and that is because some program is still holding a lock on the disk or some file on the disk. I wrote a program to show me the list of locks on any volume in the system. I started with Lockmon and noticed it wasn't to useful when it came time to 'pop out the disk'. Mainly because I was trying to use it on my hard disk! The other problem is that I cannot find out where it is documented that the handler keeps it's list of locks for a given volume. Fortunately, a consistency in the DOS helps here. The program enclosed is called 'ShowLocks' and does exactly that, it shows you all of the locks that are being held either on the volume you specify or all volumes if you type 'all'. It finds the lock list by creating a lock of it's own, which gets placed on the head of the list. Then it reads the locks by following down the linked list of BPTRs. It differs from Lockmon in that it only prints out locks for mounted volumes (they have to be mounted so that it can get the path information). Since it creates a lock to get a list of locks Lock #0 always exists (since the program created it). Only run this program on a quiet system, since the lock list can be disturbed by other processes and that can confuse the program. It's main use is to find out if your program leaves around dangling locks on files or directories. Some notes about the various DOS routines that use Locks. a) L1 = Lock(string,mode); /* You must Unlock L1 */ b) L1 = ParentDir(L2); /* You must Unlock *both* L1, and L2 */ c) L1 = CurrentDir(L2); /* You *only* unlock L1 */ d) L1 = DupLock(L2); /* You must UnLock *both* L1, and L2 */ e) One way to get the current directory without changing it... TmpLock = Lock("RAM:",ACCESS_READ); MyDir = CurrentDir(TmpLock); OriginalDir = DupLock(MyDir); TmpLock = CurrentDir(MyDir); /* Replace it */ UnLock(TmpLock); /* Unlock OriginalDir later */ The other way to get the current directory without changing it ... MyProc = FindTask(0L); OriginalDir = DupLock(MyProc->pr_CurrentDir); f) When started from the workbench, always save the original directory lock and replace it before exiting. g) Leaving a Lock keeps the icon around, UnLocking something twice causes an 0000000003. GURU. h) Exiting back to workbench after changing the CurrentDir will cause workbench to lock up. So without further ado, the tool you have been hearing about for two pages now, 'showlocks.c' (also cut the signature from the end ...) --Chuck McManis ---------------------------------cut here---------------------------- /* * showlocks.c * * Written 13-Mar-88 by Chuck McManis * Copyright 1988 Charles McManis, All rights reserved. * This file may be freely redistributed and used as long as this notice remains * with it. * * This program will list out all of the locks that are being held on the * specified volume. You can enter either a volume name or disk device. * * The output of this program is : * Lock #0 : 'Path' * Lock #1 : 'Path' * ... */ #include <exec/types.h> #include <exec/memory.h> #include <libraries/dos.h> #include <libraries/dosextens.h> extern struct DosLibrary *DOSBase; char *GetPath(); void main(argc,argv) int argc; char *argv[]; { int j,NumVols; struct DeviceList *dl,*vols[20]; struct RootNode *rn; struct DosInfo *di; char *t,tmpname[40]; if (argc != 2) { printf("Usage is : ShowLocks [all | Volumename: ]\n"); exit(0); } NumVols=0; if (strcmp(argv[1],"all") == 0) { /* Find the device list */ rn = (struct RootNode *)DOSBase->dl_Root; di = (struct DosInfo *)BADDR(rn->rn_Info); /* While searching the list we lock out Multitasking */ Forbid(); for (dl = (struct DeviceList *)BADDR(di->di_DevInfo); dl; dl = (struct DeviceList *)BADDR(dl->dl_Next)) if (dl->dl_Type == DLT_VOLUME) vols[NumVols++] = dl; Permit(); /* Back to multitasking mode */ } printf("Lock Monitor, prints out outstanding locks on a given volume.\n"); if (NumVols) { for (j=0; j<NumVols; j++) { t = (char *)BADDR(vols[j]->dl_Name); t++; /* point past the length */ strcpy(tmpname,t); /* Put the name in here... */ strcat(tmpname,":"); /* and append a colon ... */ if (vols[j]->dl_Task) { printf("Locks held on Volume %s\n",tmpname); PrintLocks(tmpname); } else printf("Volume %s is not mounted.\n",tmpname); } } else { printf("Locks held on Volume %s\n",argv[1]); PrintLocks(argv[1]); } } PrintLocks(str) char *str; { ULONG thislock; struct FileLock *fl; int i; thislock = Lock(str,ACCESS_READ); i = 0; for (fl = (struct FileLock *)(BADDR(thislock)); fl; fl = (struct FileLock *)(BADDR(fl->fl_Link))) printf(" Lock #%d : '%s'\n",i++,GetPath((ULONG)(fl) >> 2)); if (thislock) UnLock(thislock); return(0); } /* * Function GetPath() * * This function will return a pointer to a string with the path of * the passed lock. */ char * GetPath(Lck) ULONG Lck; { static char LockPath[256]; UWORD FDATA[sizeof(struct FileInfoBlock)/2+1]; ULONG CurLock,NewLock; char *s; struct FileInfoBlock *fi; /* Initialize LockPath to the NULL string */ LockPath[0] = '\0'; if ((Lck == 0) || (Lck == ~0L)) return(LockPath); /* If Lock is on root (0) return */ /* Initialize fi so that it is on a long word boundary */ if ((long)(FDATA) & 2) fi = (struct FileInfoBlock *)(&FDATA[1]); else fi = (struct FileInfoBlock *)FDATA; CurLock = DupLock(Lck); /* Make a copy of the Lock passed */ while (CurLock != NULL) { Examine(CurLock,fi); if ((CurLock != 0) && (fi->fib_DiskKey != 0)) { /* strins just prepends a string rather than append it ... */ if (strlen(LockPath)) strins(LockPath,"/"); strins(LockPath,fi->fib_FileName); } NewLock = ParentDir(CurLock); UnLock(CurLock); CurLock = NewLock; } /* Fix up the volume name to include a colon */ for (s = LockPath; *s; s++) if (*s == '/') {*s = ':'; break;} if (!(*s)) strcat(LockPath,":"); return(LockPath); } ---------------------cut here too--------------------------------- --Chuck McManis uucp: {anywhere}!sun!cmcmanis BIX: cmcmanis ARPAnet: cmcmanis@sun.com These opinions are my own and no one elses, but you knew that didn't you.
sjl@myrias.UUCP (Stuart Lomas) (03/18/88)
In message <45448@sun.uucp> cmcmanis%pepper@Sun.COM (Chuck McManis) writes: > e) One way to get the current directory without changing it... > TmpLock = Lock("RAM:",ACCESS_READ); > MyDir = CurrentDir(TmpLock); > OriginalDir = DupLock(MyDir); > TmpLock = CurrentDir(MyDir); /* Replace it */ > UnLock(TmpLock); /* Unlock OriginalDir later */ > The other way to get the current directory without changing it ... > MyProc = FindTask(0L); > OriginalDir = DupLock(MyProc->pr_CurrentDir); Both of these methods seem rather more complicated than: currentDir := Lock("",AccessRead); (I write in Modula-2, but I believe this will work the same in C) Someone asked for an example of where the Amiga documentation is unclear. This is an example - it is not at all clear from the documentation that passing Lock the null string as a file name will get you the current directory. Stuart Lomas Myrias Research Corporation Edmonton, Alberta, Canada {ihnp4,ubc-vision,rutgers}!alberta!myrias!sjl Naturally, if anything above constitutes an opinion, I claim it.
dillon@CORY.BERKELEY.EDU (Matt Dillon) (03/18/88)
:Both of these methods seem rather more complicated than: : : currentDir := Lock("",AccessRead); : :(I write in Modula-2, but I believe this will work the same in C) Yes, that works fine. An interesting variation which is also valid (which the workbench uses) is to open files by (A) lock'ing them, (B) setting the current directory to the FILELOCK, and (C) openning "": Open("", 1005). Cute, eh? -Matt