/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery. All Rights */ /* |. o.| || Reserved. This program may not be distributed without the */ /* | . | || permission of the authors: BBS: */ /* | o | || John Toebes Doug Walker Dave Baker */ /* | . |// */ /* ====== */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Lock.c - lock manipulation */ /* ActLock, ActDupLock, ActUnLock */ /*-------------------------------------------------------------------------*/ /* Structure of a Lock: */ /* struct FileLock { */ /* BPTR fl_Link; Next lock in the chain of device locks */ /* LONG fl_Key; Block number of directory or file header */ /* LONG fl_Access; Shared Read (-2) or Exclusive Write (-1) */ /* struct MsgPort * fl_Task; Handler process for Lock (Us) */ /* BPTR fl_Volume; Node in DevInfo structure for Lock */ /* }; */ /*-------------------------------------------------------------------------*/ #include "handler.h" /* create a lock to be returned */ struct FileLock *CreateLock(global, nlock, RLock, Access) GLOBAL global; NETPTR nlock; RPTR RLock; LONG Access; { struct FileLock *flock; NETPTR newnlock; if(!(flock=(struct FileLock *) DosAllocMem(global, sizeof(struct FileLock))) || !(newnlock=(NETPTR) DosAllocMem(global, sizeof(struct NetPtr))) ) return(NULL); flock->fl_Key = (LONG)newnlock; flock->fl_Access = Access; flock->fl_Task = global->n.port; flock->fl_Volume = MKBADDR(global->volume); newnlock->NetNode = nlock->NetNode; newnlock->RDevice = nlock->RDevice; newnlock->RPtr = RLock; /* Link the lock into the lock chain */ Forbid(); flock->fl_Link = global->volume->dl_Lock; global->volume->dl_Lock = MKBADDR(flock); Permit(); return(flock); } void FreeLock(global, flock) GLOBAL global; struct FileLock *flock; { struct FileLock *current, *next; if(!flock) return; Forbid(); if((current=(struct FileLock *)BADDR(global->volume->dl_Lock)) == flock) { global->volume->dl_Lock = flock->fl_Link; Permit(); BUG(("FreeLock: Head lock freed, new head = %lx\n", global->volume->dl_Lock)); } else { for(next=NULL; current && (next=(struct FileLock *)BADDR(current->fl_Link)) != flock; current = next); if(!next) { Permit(); BUG(("****************************************\n")); BUG(("******* Lock not found in chain ********\n")); BUG(("****************************************\n")); return; } else { current->fl_Link = next->fl_Link; Permit(); BUG(("Lock found and removed from chain\n")); } } /* If RDevice == NULL, we have a dummy nlock, so don't free it */ /* Otherwise, free it */ if(((NETPTR)flock->fl_Key)->RDevice) DosFreeMem((char *)flock->fl_Key); /* Free the net lock */ DosFreeMem((char *)flock); /* Free the local lock */ } void ActLock(global, pkt) GLOBAL global; struct DosPacket *pkt; /* a pointer to the dos packet sent */ /* Arg1: Lock */ /* Arg2: Name */ /* Arg3: Mode: ACCESS_READ, ACCESS_WRITE */ { NETPTR nlock; struct FileLock *flock; BUG(("Action Lock\n")); BUGBSTR("File to lock: ", pkt->dp_Arg2); /**********************************************************************/ /* If the given lock is on the local root, call the ParseName routine */ /* to determine if we need to call the remote nodes. If ParseName */ /* returns 1, we have a name of the form "NET:" and we should return */ /* a lock on the root of NET:. If it returns 0, we have a name of */ /* the form "NET:FOO" or "NET:FOO/BAR", etc and we need to call the */ /* remote node specified in the pseudo-lock returned. */ /**********************************************************************/ if((!(flock=(struct FileLock *)pkt->dp_Arg1) || !(nlock=(NETPTR)flock->fl_Key)->RDevice)) { /* ParseName returns 1 if we are locking the root. It fills in */ /* nlock with a pointer to the pseudolock for the node. The */ /* pseudolock is kept in the NetNode struct. */ /* Any leftover parts of the name are left in RP.Data as a */ /* BCPL string. */ if(ParseName(global, (char *)pkt->dp_Arg2, &nlock, global->RP.Data)) { BUG(("ActLock: Returning lock on root\n")); /* Return lock on root */ /* ParseName has put the pseudolock for the root into nlock */ pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock, NULL, pkt->dp_Arg3)); return; } else if(!nlock) { BUG(("ActLock: Couldn't find node\n")); pkt->dp_Res1 = NULL; pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND; return; } #if DEBUG else BUG(("ActLock: got nlock, falling through\n")); #endif } else { BUGBSTR("ActLock: Relative open, node ", nlock->NetNode->name); /* We are doing a relative open - put filename in Data */ MBSTR(pkt->dp_Arg2, global->RP.Data); } global->RP.Type = pkt->dp_Type; global->RP.Arg1 = (LONG)nlock->RPtr; global->RP.Arg3 = pkt->dp_Arg3; global->RP.DLen = BSTRLEN(global->RP.Data)+1; if(global->RP.DLen == 1) global->RP.DLen = 0; if(!RemotePacket(global, nlock) && pkt->dp_Res1) { BUG(("ActLock: Returned RPTR is %lx\n", pkt->dp_Res1)); pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock, (RPTR)pkt->dp_Res1, pkt->dp_Arg3)); } } void ActDupLock(global,pkt) GLOBAL global; struct DosPacket *pkt; /* a pointer to the dos packet sent */ { NETPTR nlock; struct FileLock *flock; BUG(("Action DupLock\n")); /* If this is a lock on the local root, it is a special case */ if((!(flock=(struct FileLock *)pkt->dp_Arg1) || !(nlock=(NETPTR)flock->fl_Key)->RDevice)) { pkt->dp_Res1 = NULL; if(!flock) return; /* Dup of null lock is null lock */ goto GETLOCK; /* Dup of real lock on root is real lock (?)*/ } global->RP.Type = pkt->dp_Type; global->RP.Arg1 = (LONG)nlock->RPtr; global->RP.DLen = 0; if(!RemotePacket(global, nlock) && pkt->dp_Res1) { GETLOCK: pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock, (RPTR)pkt->dp_Res1, flock->fl_Access)); } } void ActUnLock(global, pkt) GLOBAL global; struct DosPacket *pkt; /* a pointer to the dos packet sent */ { NETPTR nlock; struct FileLock *flock; BUG(("Action UnLock\n")); if(!(flock = (struct FileLock *)pkt->dp_Arg1)) { /* No lock - do nothing */ pkt->dp_Res1 = DOS_TRUE; return; } /* If this lock exists on a remote node, delete it */ if((nlock=(NETPTR)flock->fl_Key)->RDevice) { global->RP.Type = pkt->dp_Type; global->RP.Arg1 = (LONG)nlock->RPtr; global->RP.DLen = 0; RemotePacket(global, nlock); } else pkt->dp_Res1 = DOS_TRUE; FreeLock(global, flock); } int ParseName(global, name, nlock, outname) GLOBAL global; char *name; NETPTR *nlock; char *outname; { int len, cur; struct NetNode *node; BUGBSTR("ParseName: Parsing name ", name); for(len=*(name++), cur=0; len && *name != '/'; len--, name++) { if(*name==':') cur=0; else outname[cur++] = *name; } outname[cur] = '\0'; if(len>0 && *name == '/') name++, len--; if(len <= 1 && cur == 0) { /* It is the root of NET: */ *nlock = &global->netchain.RootLock; return(1); } /* We have a network node name - find it */ node = FindNode(global, outname); /* OK, check to see if it is a .info file for a node */ if(!node && cur >= 6 && !stricmp(outname+cur-5, ".info")) { outname[cur-5] = '\0'; if(node = FindNode(global, outname)) { BUG(("Got a .info file for node '%s'\n", outname)); name = "Node.rinfo"; len = 10; } } /* No node found - return null nlock */ if(!node) { BUG(("ParseName: No node found, nlock is NULL\n")); *nlock = NULL; } else { /* Node found - return template lock */ *nlock = &node->RootLock; BUGBSTR("ParseName: Sending packet to node ", node->name); } /* Move the rest of the name into outname as a BSTR */ outname[0] = (char)len+1; outname[1] = ':'; if(len) MQ(name, outname+2, len); outname[len+2] = '\0'; BUG(("Remote filename: len %d text '%s'\n", (int)*outname, outname+1)); return(0); } struct NetNode *FindNode(global, name) GLOBAL global; char *name; { struct NetNode *node; for(node=global->netchain.next; node; node=node->next) if(!stricmp(name, node->name+1)) break; return(node); }