home *** CD-ROM | disk | FTP | other *** search
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* |_o_o|\\ Copyright (c) 1987 The Software Distillery. All Rights Reserved */
- /* |. o.| || This program may not be distributed without the permission of */
- /* | . | || the authors: BBS: */
- /* | o | || John Toebes Dave Baker John Mainwaring */
- /* | . |// */
- /* ====== */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Change History */
- /* 10-JUN-88 JAT - Corrected code which handles file extension blocks */
- /* the AmigaDos technical reference manual is incorrect in */
- /* its description of the HighSeq and DataBlockCount fields*/
- /* */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* AmigaDos 1.2 support routines */
-
- #include "handler.h"
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: IsSameName */
- /* Purpose: Compare a BSTR to a string/length for a directory match */
- /* NOTE: Case is insensitive */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int IsSameName(bstr, name, len)
- register char * bstr;
- register char * name;
- register int len;
- {
- register char c1, c2;
-
- /* Make sure they are the same length */
- if (len != *bstr++)
- {
- BUG(("Length mismatch B=%ld n=%ld\n", *--bstr, len));
- return(0);
- }
-
- /* Compare all the characters (ignoring case) */
- while(len--)
- {
- /* Get the next characters to compare */
- c1 = *name++; c2 = *bstr++;
- /* Convert to lower case */
- if ((c1 >= 'A') && (c1 <= 'Z')) c1 += ('a'-'A');
- if ((c2 >= 'A') && (c2 <= 'Z')) c2 += ('a'-'A');
- /* and make sure they match */
- if (c1 != c2) return(0);
- }
-
- /* Seems to work so let it pass... */
- return(1);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: NextKey */
- /* Purpose: Find next key in directory rootkey starting at position key. */
- /* Note: Key == 0 searches for first key. Traverses all hash chains. */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY NextKey(global, key, info, rootkey)
- GLOBAL global;
- struct FileInfoBlock *info;
- KEY key, rootkey;
- {
- KEY limit;
- int hashval;
- struct DirBlock *block;
-
- limit = 0;
-
- if (key == 0)
- hashval = 0;
- else
- {
- /* Note that we at least can count on the directory entries being in */
- /* ascending order. This has two effects. First it means that we are*/
- /* not running wild with back and forth seeks. Secondly it means that*/
- /* if something is deleted, we can figure out what entries we already */
- /* gave them by just a simple key comparison */
-
- /* Already doing a directory, might as well continue on */
- /* first locate the last block they looked at */
- if ((block = (struct DirBlock *)GetBlock(global, key)) == NULL)
- return(0);
-
- hashval = hash(info->fib_FileName+1, info->fib_FileName[0]);
-
- /* Now make sure it is the same block that we examined last time */
- /* Make sure it is a directory entry belonging to the same parent */
- /* it isn't safe to compare the name as case might have changed */
- /* although we could compare the hash for the name. */
- if ((block->db_Type != T_SHORT) ||
- (block->db_Parent != rootkey) ||
- (hash(block->db_Name+1, block->db_Name[0]) != hashval))
- {
- /* Well, something is certainly wrong here. We have to go back */
- /* and start at the beginning of the current hash chain */
- limit = key;
- key = 0;
- }
- else
- {
- /* If there is nothing on the chain then tell them to look at the */
- /* next hash value chain */
- key = block->db_HashChain;
- hashval++;
- }
- }
-
- /* did we find something or will we have to look again */
- if (key == 0)
- {
- /* OK, now we need to go to the root and search the hash chains */
- if ((block = (struct DirBlock *)GetBlock(global,rootkey)) == NULL)
- /* Funny, couldn't find the parent directory so just fail the */
- /* search for the next key */
- return(0);
-
- while(hashval < HASHTABLESIZE)
- {
- if (key = block->db_HashTable[hashval++])
- {
- if (key > limit)
- /* Had a hit on the key so return it. */
- break;
-
- /* Walk down the list until we hit an entry greater than the */
- /* limit or the end of the list */
- while((key != 0) && (key < limit))
- {
- if ((block = (struct DirBlock *)GetBlock(global, key)) == NULL)
- return(0);
- key = block->db_HashChain;
- }
-
- /* Relocate the parent block */
- limit = 0;
- if ((block = (struct DirBlock *)GetBlock(global,rootkey)) == NULL)
- /* Funny, couldn't find the parent directory so just fail the */
- /* search for the next key */
- return(0);
- }
- }
- }
- /* if we didn't get anything useful, key is 0 */
- return (key);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: ParentKey */
- /* Purpose: Find key of parent directory of input key */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY ParentKey(global, key)
- GLOBAL global;
- KEY key;
- {
- struct DirBlock *block;
-
- if (key == 0 ||
- (block = (struct DirBlock *)GetBlock(global,key)) == NULL)
- return(0);
-
- return(block->db_Parent);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: hash */
- /* Purpose: Compute the hash value of a name */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int hash(name, len)
- unsigned char *name; /* pointer to str to hash on */
- int len;
- {
- int c;
- int hashval;
-
- /* Now compute a hashvalue for the result */
- hashval = len;
- while(len--)
- {
- c = *name++;
- if (c >= 'a' && c <= 'z')
- c = c - 'a' + 'A';
- hashval = ((hashval * 13 + c ) & 0x7ff);
- }
-
- return(hashval % HASHTABLESIZE);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: Parse */
- /* Purpose: Separate out the next node in a file name */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int parse(name, len, buf)
- char **name;
- int *len;
- register char *buf;
- {
- register int left;
- register int c;
- register int curlen;
-
- curlen = 0;
- left = *len;
-
- memset(buf, 0, 32);
-
- while((--left >= 0) && ((c = *(*name)++) != '/') )
- {
- if (c == ':')
- {
- /* got a volume name terminator. We need to throw everything away */
- curlen = 0;
- buf[++curlen] = c;
- break;
- }
- else
- buf[++curlen] = c;
- }
-
- /* update our parse length */
- if (left < 0)
- *len = 0;
- else
- *len = left;
-
- buf[0] = curlen;
-
- BUGLSTR("Parsed Name:", buf+1, curlen);
-
- /* Now compute a hashvalue for the result */
- return(hash(buf+1, curlen));
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: GetProtect */
- /* Purpose: Return the protection bits associated with a file entry */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int GetProtect(global,key)
- GLOBAL global;
- KEY key;
- {
- struct DirBlock *block;
-
- block = (struct DirBlock *)GetBlock(global,key);
- if (block == NULL)
- return(FIBF_WRITE|FIBF_READ|FIBF_DELETE|FIBF_EXECUTE);
-
- return(block->db_Protect);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: SetProtect */
- /* Purpose: Set the protection bits for a file */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int SetProtect(global, key, prot)
- GLOBAL global;
- KEY key;
- long prot;
- {
- struct DirBlock *block;
-
- if (key == 0 ||
- (block = (struct DirBlock *)ModBlock(global,key)) == NULL)
- return(DOS_FALSE);
-
- block->db_Protect = prot;
- return(DOS_TRUE);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: GetType */
- /* Purpose: Determine the type of a file entry */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int GetType(global, key)
- GLOBAL global;
- KEY key;
- {
- struct DirBlock *block;
-
- block = (struct DirBlock *)GetBlock(global,key);
- if (block == NULL)
- return(0); /* A truely invalid type */
-
- BUG(("GetType: addr %08lx for key %ld\n", block, key));
- return(block->db_SecondaryType);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: SetCommentStr */
- /* Purpose: Set the comment string for a file */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int SetCommentStr(global, key, comment)
- GLOBAL global;
- KEY key;
- char *comment;
- {
- struct DirBlock *block;
-
- if (key == 0 ||
- (block = (struct DirBlock *)ModBlock(global,key)) == NULL)
- return(DOS_FALSE);
-
- memcpy((char *)block->db_Comment, comment, (*comment)+1 );
- return(DOS_TRUE);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: GetInfo */
- /* Purpose: Copy the file information for a dos info block */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int GetInfo(global, key, info)
- GLOBAL global;
- KEY key;
- register struct FileInfoBlock *info;
- {
- register struct DirBlock *block;
- char *p;
-
- /* get the block associated with the key */
- if ((key == 0) ||
- ((block = (struct DirBlock *)GetBlock(global,key)) == NULL))
- return(DOS_FALSE);
-
- /* It would be prudent here to check the type of block and see that it */
- /* Is a true file entry block */
-
- /* Now copy over the information they want */
- info->fib_DiskKey = key;
- info->fib_EntryType =
- info->fib_DirEntryType = block->db_SecondaryType;
-
- /* Set the entry type to 2 to make dir happy */
- if (info->fib_EntryType == 1)
- info->fib_EntryType =
- info->fib_DirEntryType = 2;
-
- p = (char *)block->db_Name;
-
- memcpy(info->fib_FileName, p, (*p)+1);
- info->fib_Protection = block->db_Protect;
- info->fib_Size = block->db_Size;
- info->fib_NumBlocks = (block->db_Size + (BLOCKSIZE-1))/BLOCKSIZE;
- info->fib_Date.ds_Days = block->db_Days;
- info->fib_Date.ds_Minute = block->db_Minutes;
- info->fib_Date.ds_Tick = block->db_Ticks;
-
- p = (char *)block->db_Comment;
- memcpy(info->fib_Comment, p, (*p)+1 );
-
- #if 0
- BUG(("Done setting up info for key %ld\n",info->fib_DiskKey));
- BUG(("Entry=%ld Protect=%ld Size=%ld Blocks=%ld\n", info->fib_DirEntryType, info->fib_Protection, info->fib_Size, info->fib_NumBlocks));
- BUG(("Day=%ld Min=%ld Tick=%ld\n", info->fib_Date.ds_Days, info->fib_Date.ds_Minute, info->fib_Date.ds_Tick));
- BUGBSTR("Name :", info->fib_FileName);
- BUGBSTR("Comment :", info->fib_Comment);
- #endif
-
- return(DOS_TRUE);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: FindDir */
- /* Purpose: Find a Directory associated with a file and parse out the name */
- /* of the file from the file string */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY FindDir(global, key, namep, lenp)
- GLOBAL global;
- KEY key;
- char **namep;
- int *lenp;
- {
- int len;
- char *p, *t;
- register struct DirBlock *block;
- char namebuf[32];
- int hashval;
-
- len = *lenp;
- p = *namep + len - 1;
-
- /* Skip to the last colon or / in the name */
- while ((*p != ':') && (*p != '/') && len) { p--; len--; }
- *lenp -= len;
-
- t = p;
- if (len) t++;
- /* Are they attempting to access '.' or '..' ? */
- if (*t == '.' &&
- ((*lenp == 1) ||
- ((*lenp == 2) && (*(t+1) == '.'))))
- {
- /* Yes, so treat it as part of the directory */
- len += *lenp;
- *lenp = 0;
- }
-
- BUGLSTR("Locate: Path is :", *namep, len);
-
- /* Now run through the string searching the directory */
- while(len && key)
- {
- /* first go to the root of the directory they asked for */
- block = (struct DirBlock *)GetBlock(global,key);
-
- if (block == NULL)
- {
- BUG(("FindDir: Error accessing block %ld\n", key));
- return(0);
- }
-
- if ((block->db_SecondaryType != ST_ROOT) &&
- (block->db_SecondaryType != ST_USERDIR))
- {
- /* they want to traverse a file as a directory - give them hell */
- global->pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
- return(0);
- }
-
- /* break down the next subcomponent of the name */
- hashval = parse(namep, &len, namebuf);
-
- BUGBSTR("Parsed Name :", namebuf);
- BUG(("Hashval = %ld\n", hashval));
-
- /* Did they specify the root directory ? */
- if ((namebuf[0] == 1) && (namebuf[1] == ':'))
- {
- key = global->Root;
- BUG(("Moving to root: %ld\n", key));
- }
-
- else if ((namebuf[0] == 0) ||
- ((namebuf[0] == 2) && (namebuf[1]=='.') && (namebuf[2] == '.')))
- {
- key = block->db_Parent;
- BUG(("Moving to paremt: %ld\n", key));
- }
-
- else if ((namebuf[0] != 1) || (namebuf[1] != '.'))
- {
- /* Search the current block for the given name */
- for( key = block->db_HashTable[hashval]; key != 0;
- key = block->db_HashChain)
- {
- block = (struct DirBlock *)GetBlock(global,key);
- if (block == NULL)
- {
- BUG(("FindDir: Can't get block %ld\n", key));
- return(0);
- }
-
- BUGBSTR("Block name:", block->db_Name);
- if (IsSameName(block->db_Name, (char *)namebuf+1, namebuf[0]))
- break;
- }
- }
- }
-
- if (key == 0)
- global->pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
-
- BUG(("locate: key is %ld\n", key));
- return(key);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: FindEntry */
- /* Purpose: Locate an entry in a directory */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY FindEntry(global, key, name, len)
- GLOBAL global;
- KEY key;
- char *name;
- int len;
- {
- int hashval;
- struct DirBlock *block;
-
- BUGLSTR("FindEntry: Name is ", name, len);
-
- if (len == 0)
- {
- BUG(("Length is zero, returning key=%ld\n", key));
- return(key);
- }
-
- hashval = hash(name, len);
- /* first go to the root of the directory they asked for */
- if ((block = (struct DirBlock *)GetBlock(global,key)) == NULL)
- return(0);
-
- BUG(("Starting search for hash=%ld from key=%ld\n", hashval, key));
-
- if ((block->db_SecondaryType != ST_ROOT) &&
- (block->db_SecondaryType != ST_USERDIR))
- {
- BUG(("Secondary type %ld bad for key %ld\n", block->db_SecondaryType, key));
- /* they want to traverse a file as a directory - give them hell */
- global->pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
- return(0);
- }
-
- global->prevkey = 0;
-
- /* Search the current block for the given name */
- for( key = block->db_HashTable[hashval]; key != 0;
- key = block->db_HashChain)
- {
- if ((block = (struct DirBlock *)GetBlock(global,key)) == NULL)
- return(0);
-
- BUGBSTR("Block name:", block->db_Name);
- if (IsSameName(block->db_Name, name, len))
- break;
-
- global->prevkey = key;
- }
-
- if (!key)
- global->pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
-
- return(key);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: MakeEntry */
- /* Purpose: Create a new entry for a file */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY MakeEntry(global, key, name, len, type)
- GLOBAL global;
- KEY key;
- char *name;
- int len;
- int type;
- {
- int hashval;
- KEY newkey, nextkey;
- struct DirBlock *block;
- LONG *zeroptr;
- zeroptr = 0;
-
- BUGLSTR("MakeEntry: name ", name, len);
-
- hashval = hash(name, len);
-
- /* first go to the root of the directory they asked for */
- block = (struct DirBlock *)GetBlock(global,key);
-
- /* When all else fails pop up to let it be handled */
- if (block == NULL) return(0);
-
- if ((block->db_SecondaryType != ST_ROOT) &&
- (block->db_SecondaryType != ST_USERDIR))
- {
- /* they want to traverse a file as a directory - give them hell */
- global->pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
- return(0);
- }
-
- /* Get us a block to put the newly created item */
- if (!(newkey = AllocateBlock(global, key, type)))
- {
- BUG(("MakeEntry:Unable to allocate a block %ld\n", newkey));
- global->pkt->dp_Res2 = ERROR_DISK_FULL;
- return(0);
- }
-
- /* try to put block into right place in parent directory */
- if ((nextkey = LinkDir(global, key, newkey, hashval)) == -1)
- {
- FreeBlock(global, newkey);
- return(0); /* invalid key - admission of failure */
- }
- BUG(("MakeEntry: new entry %d points to successor %d\n", newkey, nextkey));
-
- /* Find the newly created block and fill it in */
- block = (struct DirBlock *)ModBlock(global, newkey);
- if (block == NULL)
- {
- /* Actually getting an error here is quite fatal because we already */
- /* modified the directory entry. We need to figure out a way to back */
- /* out of the creation. The only situation that should cause this is */
- /* if the allocated block gets flushed out to disk and we are unable */
- /* to read it in. In this case it is quite likely that the media is */
- /* not usable. However we eventually may have to handle this case */
- FreeBlock(global, newkey);
- return(0);
- }
- memset((char *)block, 0, sizeof(struct DirBlock));
-
- BUG(("MakeEntry: New entry %ld at %08lx\n", newkey, block));
- block->db_HashChain = nextkey;
-
- /* Fill in the remainder of the information */
- block->db_Type = T_SHORT;
- block->db_OwnKey = newkey;
- block->db_SecondaryType = type;
- memcpy(((char *)block->db_Name)+1, name, len);
- *(char *)&block->db_Name[0] = len;
- block->db_Parent = key;
- SetDateInfo(global, block);
- return(newkey);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: LocateEntry */
- /* Purpose: Find an file entry */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY LocateEntry(global, key, name)
- GLOBAL global;
- KEY key;
- char *name;
- {
- int len;
-
- len = *name++;
-
- BUGLSTR("LocateEntry: Full Name is:", name, len);
- if (!(key = FindDir(global, key, &name, &len)))
- return(0);
-
- BUGLSTR("LocateEntry: name ", name, len);
-
- return(FindEntry(global, key, name, len));
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: CreateEntry */
- /* Purpose: Create a new file entry */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY CreateEntry(global, key, name, mode, type)
- GLOBAL global;
- KEY key;
- char *name;
- int mode;
- int type;
- {
- int len;
- KEY newkey;
- struct DirBlock *block;
-
- len = *name++;
- BUGLSTR("CreateEntry: Name ", name, len);
-
- if (!(key = FindDir(global, key, &name, &len)))
- return(0);
-
- BUGLSTR("CreateEntry: Parsed Name ", name, len);
- if (newkey = FindEntry(global, key, name, len))
- {
- /* Entry already exists, may need to blow it away */
- if (mode == NEWFILE)
- {
- global->pkt->dp_Res2 = ERROR_OBJECT_EXISTS;
- return(0);
- }
- #if 0
- /* Although logical course of action, the current filing system seems */
- /* to not exactly work this way. */
- if (GetProtect(global, newkey) & FIBF_DELETE)
- {
- global->pkt->dp_Res2 = ERROR_DELETE_PROTECTED;
- return(0);
- }
- #endif
- if (GetProtect(global, newkey) & FIBF_WRITE)
- {
- global->pkt->dp_Res2 = ERROR_WRITE_PROTECTED;
- return(0);
- }
- if ((GetType(global, newkey) == ST_USERDIR) || (type == ST_USERDIR))
- {
- global->pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
- return(0);
- }
- FreeDataChain(global, newkey);
-
- /* Also we need to update the name information in the file */
- /* This allows them to change the case of the name. Note that by */
- /* doing this in place we preserve all the comment information and */
- /* attributes of the old entry. Also since the entry doesn't move on */
- /* disk we can keep it in the same plae on the hash chain. */
- block = (struct DirBlock *)ModBlock(global, newkey);
- if (block != NULL)
- {
- memcpy(((char *)block->db_Name)+1, name, len);
- *(char *)&block->db_Name[0] = len;
-
- /* Clear the archive bit so backup programs know it has been modified */
- block->db_Protect &= ~FIBF_ARCHIVE;
- }
- }
- else
- {
- /* We have a brand new file here, so make us an entry for it */
- newkey = MakeEntry(global, key, name, len, type);
- BUG(("CreateEntry: newkey is %ld\n", newkey));
- }
- return(newkey);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: FreeDataChain */
- /* Purpose: Truncate the data chain for a file */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int FreeDataChain(global, basekey)
- GLOBAL global;
- KEY basekey;
- {
- KEY key, savekey;
- long i;
- struct FileBlock *block;
-
- key = basekey;
- while(key)
- {
- if ((block = (struct FileBlock *)GetBlock(global, key)) == NULL)
- return(0);
-
- for (i = 0; i < block->fb_HighSeq; i++)
- FreeBlock(global, block->fb_DataBlock[(BLOCKSPERENTRY-1)-i]);
- savekey = block->fb_Extension;
- BUG(("FreeDataChain: Base:%ld Key:%ld next:%ld\n", basekey, key, savekey));
- if (key != basekey)
- FreeBlock(global, key);
- key = savekey;
- }
-
- if ((block = (struct FileBlock *)ModBlock(global, basekey)) == NULL)
- {
- return(0);
- }
-
- block->fb_FirstData = block->fb_DataBlockCount = block->fb_HighSeq = 0;
- block->fb_Extension = 0;
- block->fb_Size = 0;
- return(1);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: SeekDataChain */
- /* Purpose: Locate a block in a file data chain */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY SeekDataChain(global, efh, num)
- GLOBAL global;
- struct EFileHandle *efh;
- long num;
- {
- struct FileBlock *block;
- KEY key;
- long off;
- long entryblock;
-
- if (num-- <= 0)
- {
- BUG(("Attempt to seek to %ld on %08lx\n", num+1, efh));
- global->pkt->dp_Res2 = ERROR_SEEK_ERROR;
- return(0);
- }
-
- entryblock = num/BLOCKSPERENTRY;
- BUG(("SeekDataChain: num=%ld entry=%ld cur=%ld\n",num,entryblock,efh->efh_CurExtBlock));
-
- if (entryblock != efh->efh_CurExtBlock)
- {
- /* Are we seeking forward? */
- BUG(("Forward seek\n"));
- if (entryblock > efh->efh_CurExtBlock)
- {
- entryblock -= efh->efh_CurExtBlock;
- key = efh->efh_ExtBlockKey;
- efh->efh_CurExtBlock += entryblock;
- }
- else
- {
- BUG(("Must seek from beginning\n"));
- /* Need to seek from beginning to target */
- efh->efh_CurExtBlock = entryblock;
- key = efh->efh_Lock->fl_Key;
- }
- while(key && entryblock--)
- {
- if ((block = (struct FileBlock *)GetBlock(global, key)) == NULL)
- return(0);
- key = block->fb_Extension;
- }
- efh->efh_ExtBlockKey = key;
- }
- else
- key = efh->efh_ExtBlockKey;
-
- if (key)
- {
- off = num - (efh->efh_CurExtBlock * BLOCKSPERENTRY);
-
- if ((block = (struct FileBlock *)GetBlock(global, key)) == NULL)
- return(0);
-
- if (off >= block->fb_HighSeq)
- {
- BUG(("SeekDataChain: %ld Out of range %ld for %ld\n", off, block->fb_HighSeq, off));
- key = 0;
- }
- else
- key = block->fb_DataBlock[(BLOCKSPERENTRY-1) - off];
- }
-
- BUG(("SeekDataChain: Returning block %ld\n", key));
- return(key);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: AppendDataChain */
- /* Purpose: Allocate a new block to extend a file data chain */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY AppendDataChain(global, efh, highseq)
- GLOBAL global;
- struct EFileHandle *efh;
- long highseq;
- {
- KEY key, blockkey, newkey;
- struct FileBlock *block;
- struct DataBlock *data;
- KEY firstdata, filekey;
-
- filekey = efh->efh_Lock->fl_Key;
- if ((block = (struct FileBlock *)GetBlock(global, filekey)) == NULL)
- {
- BUG(("Couldn't locate the base node for key %ld\n", filekey))
- return(0);
- }
-
- firstdata = block->fb_FirstData;
- if (highseq)
- {
- key = SeekDataChain(global, efh, highseq);
- if (key == 0)
- {
- /* Too far past end of file, issue an error */
- BUG(("Append Error: efh:%08lx seq=%ld\n", efh, highseq));
- global->pkt->dp_Res1 = DOS_FALSE;
- global->pkt->dp_Res2 = ERROR_SEEK_ERROR;
- return(0);
- }
- }
- else
- key = filekey;
-
- /* Get the block to put the data into */
- if ((newkey = AllocateBlock(global, key, T_DATA)) == 0)
- return(0);
-
- BUG(("Append: New data block #%ld at %ld Ext = %ld\n", highseq, newkey, efh->efh_ExtBlockKey));
- if ((block = (struct FileBlock *)
- ModBlock(global, efh->efh_ExtBlockKey)) == NULL)
- goto appenderr;
-
- if (block->fb_HighSeq != BLOCKSPERENTRY)
- {
- /* Will fit in the current file chain so put it there and go on */
- block->fb_DataBlock[(BLOCKSPERENTRY-1)-block->fb_HighSeq] = newkey;
- block->fb_HighSeq++;
- }
- else
- {
- /* need to allocate another extension chain */
- BUG(("Need to allocate extension\n"));
- if ((blockkey =
- AllocateBlock(global, efh->efh_ExtBlockKey, T_SHORT)) == 0)
- goto appenderr;
-
- /* Succeeded so initialize the new extension chain */
- if ((block = (struct FileBlock *)
- ModBlock(global, efh->efh_ExtBlockKey)) == NULL)
- goto initerr;
-
- block->fb_Extension = blockkey;
-
- if ((block = (struct FileBlock *)ModBlock(global, blockkey)) == NULL)
- {
- /* odds of this situation are extremely low since allocateblock */
- /* was supposed to set up the sitution, but let's be safe */
- initerr:
- FreeBlock(global, blockkey);
- appenderr:
- FreeBlock(global, newkey);
- return(0);
- }
-
- memset((char *)block, 0, sizeof(struct FileBlock));
- block->fb_Type = T_LIST;
- block->fb_OwnKey = blockkey;
- block->fb_DataBlockCount = 0;
- block->fb_HighSeq = 1;
- block->fb_FirstData = firstdata;
- block->fb_Parent = filekey;
- block->fb_Extension = 0;
- block->fb_DataBlock[BLOCKSPERENTRY-1] = newkey;
- block->fb_SecondaryType = ST_FILE;
-
- efh->efh_CurExtBlock++;
- efh->efh_ExtBlockKey = blockkey;
- }
-
- /* Go back and put the forward chain links in */
- if ((block = (struct FileBlock *)ModBlock(global, key)) == NULL)
- {
- BUG(("Unable to mod previous block %ld\n", key));
- return(0);
- }
-
- block->fb_FirstData = newkey;
-
- /* Now lastly we need to set up the new data block */
- if ((data = (struct DataBlock *)ModBlock(global, newkey)) == NULL)
- {
- BUG(("Unable to locate the new data block\n"));
- return(0);
- }
-
- memset((char *)data, 0, sizeof(struct DataBlock));
- data->db_Type = T_DATA;
- data->db_Header = filekey;
- data->db_SeqNum = highseq+1;
- data->db_DataSize = 0; /* Since there is nothing in it yet */
- data->db_NextData = 0; /* This is the last block in the file */
- return(newkey);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: PUTDATA */
- /* Purpose: Stuff file data into a data block */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- void PUTDATA(block, pos, data, len)
- char *block;
- long pos;
- char *data;
- long len;
- {
- struct DataBlock *db = (struct DataBlock *)block;
- memcpy(((char *)db->db_Data) + pos, data, len);
- if ((len+pos) > db->db_DataSize)
- db->db_DataSize = len+pos;
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: GETDATA */
- /* Purpose: Extract file data from a data block */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- void GETDATA(data, len, block, pos)
- char *data;
- long len;
- char *block;
- long pos;
- {
- struct DataBlock *db = (struct DataBlock *)block;
- memcpy(data, ((char *)db->db_Data) + pos, len);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: GetFileSize */
- /* Purpose: Determine the current length of a file */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- long GetFileSize(global, efh)
- GLOBAL global;
- EFH efh;
- {
- struct DirBlock *db;
-
- if ((db = (struct DirBlock *)GetBlock(global, efh->efh_Lock->fl_Key)) == NULL)
- /* Couldn't read the directory entry so let them know */
- return(-1);
-
- return(db->db_Size);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: UpdateFile */
- /* Purpose: Update the directory entry to indicate the current file length */
- /* The date time stamp is also updated */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int UpdateFile(global, efh, blknum, blkpos)
- GLOBAL global;
- EFH efh;
- long blknum;
- long blkpos;
- {
- struct DirBlock *db;
-
- BUG(("UpdateFile: %ld to %ld/%ld\n", efh->efh_Lock->fl_Key, blknum, blkpos));
- if ((db = (struct DirBlock *)ModBlock(global, efh->efh_Lock->fl_Key)) == NULL)
- /* Couldn't read the directory entry so let them know */
- return(0);
-
- db->db_Size = ((blknum-1)*BLOCKSIZE) + blkpos;
-
- /* Clear the archive bit so the backup programs know it has been modified */
- db->db_Protect &= ~FIBF_ARCHIVE;
-
- SetDateInfo(global, db);
-
- return(1);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: BlockKey */
- /* Purpose: Return the key associated with a specific block in a file. */
- /* If the block is one past the end of the file it will extend */
- /* the file by one block */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY BlockKey(global, efh, seq, writemode)
- GLOBAL global;
- EFH efh;
- long seq;
- int writemode;
- {
- KEY key;
-
- key = SeekDataChain(global, efh, seq);
-
- /* If we didn't find an already existing block when we are attempting to */
- /* write to the block we want to append to the end of the file. Note that */
- /* the test of seq is just an additional paranoid protection */
- if (writemode && (key == 0) && seq)
- {
- BUG(("BlockKey: Extending file to %ld\n", seq));
- key = AppendDataChain(global, efh, seq-1);
- }
-
- BUG(("BlockKey: Returning %ld\n", key));
- return(key);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: SetDateInfo */
- /* Purpose: Set the modified date/time stamp on the current entry */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- void SetDateInfo(global, db)
- GLOBAL global;
- struct DirBlock *db;
- {
- /* Note that this presumes DOS is around to do the data stamping */
- #if 0
- DateStamp((long *)&db->db_Days);
- #else
- GetDateStamp(global, (struct DateStamp *)&db->db_Days); /* Just to experiment */
- #endif
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: RenameDisk */
- /* Purpose: Change the current disk label */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int RenameDisk(global, name)
- GLOBAL global;
- char *name;
- {
- struct RootBlock *root;
- int len;
-
- if ((global->volume == NULL) ||
- ((root = (struct RootBlock *)global->Root) == NULL))
- return(DOS_FALSE);
-
- /* Make sure we don't get a name to big */
- len = *name++;
- if (len >= NAMESIZE)
- len = NAMESIZE - 1;
-
- root->rb_Name[0] = len;
- memcpy(root->rb_Name+1, name, len);
-
- return(DOS_TRUE);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: DeleteEntry */
- /* Purpose: Remove an directory entry */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int DeleteEntry(global, key, name)
- GLOBAL global;
- KEY key;
- char *name;
- {
- int len;
- int i;
- KEY parent, nextkey;
- struct DirBlock *block;
-
- len = *name++;
-
- /* First see if the entry really exists */
- if (!(parent = FindDir(global, key, &name, &len)))
- return(DOS_FALSE);
-
- /* Ok, we got the directory, is the file or entry there ? */
- if (!(key = FindEntry(global, parent, name, len)))
- return(DOS_FALSE);
-
- /* Make sure they haven't protected it against deletion */
- if (GetProtect(global, key) & FIBF_DELETE)
- {
- global->pkt->dp_Res2 = ERROR_DELETE_PROTECTED;
- return(DOS_FALSE);
- }
-
- /* Gee, it is there, now we need to go through and delete it */
- /* First we get rid of the data chain for the file */
- switch(GetType(global, key)) {
- case ST_USERDIR:
- if ((block = (struct DirBlock *)GetBlock(global, key)) == NULL)
- return(DOS_FALSE);
-
- /* Make sure the directory is empty first */
- for (i= 0; i < HASHTABLESIZE; i++)
- if (block->db_HashTable[i] != 0)
- {
- global->pkt->dp_Res2 = ERROR_DIRECTORY_NOT_EMPTY;
- return(DOS_FALSE);
- }
- break;
-
- case ST_FILE:
- if (!FreeDataChain(global, key))
- {
- BUG(("Unable to release the data chain for the file %ld\n", key));
- return(DOS_FALSE);
- }
- break;
-
- default:
- BUG(("What type of a thing is this they are deleting\n"));
- global->pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
- return(DOS_FALSE);
- /* break; compiler doesn't really like this */
- }
-
- /* Now we want to remove the entry from the directory */
- /* to do this we want to find either the parent or the previous entry */
- /* When we called FindEntry, it filled in global->prevkey with the */
- /* previous hash chain entry if we were in the list OR it is 0 which */
- /* means that we need to unlink it from our parent */
- /* First we need to get the next entry in the hash chain */
- if ((block = (struct DirBlock *)ModBlock(global, key)) == NULL)
- return(DOS_FALSE);
-
- /* Just to be nice, mark it as deleted */
- block->db_Type |= T_DELETED;
- nextkey = block->db_HashChain;
-
- if (global->prevkey)
- {
- if ((block = (struct DirBlock *)ModBlock(global, global->prevkey)) == NULL)
- return(DOS_FALSE);
- block->db_HashChain = nextkey;
- if ((block = (struct DirBlock *)ModBlock(global, parent)) == NULL)
- return(DOS_FALSE);
- }
- else
- {
- if ((block = (struct DirBlock *)ModBlock(global, parent)) == NULL)
- return(DOS_FALSE);
- block->db_HashTable[hash(name, len)] = nextkey;
- }
-
- /* We are now at the parent block, so update the date time information on it */
- SetDateInfo(global, block);
-
- /* Also, mark the directory block for the file as empty */
- FreeBlock(global, key);
-
- return(DOS_TRUE);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: RenameEntry */
- /* Purpose: Implement most of ActRenameEntry. Check for valid parameters */
- /* then relink entry block to new directory location. */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- int RenameEntry(global, fromkey, tokey, fromname, toname)
- GLOBAL global;
- KEY fromkey, tokey;
- char *fromname, *toname;
- {
- struct DirBlock *block;
- KEY parentkey, prevkey, nextkey, dirkey, ancestor;
- int hashval, len;
-
- if (!(fromkey = LocateEntry(global, fromkey, fromname)))
- return(DOS_FALSE);
- /* get some useful info while it's available, we're sure to need it */
- prevkey = global->prevkey;
- if ((block = (struct DirBlock *)GetBlock(global, fromkey)) == NULL)
- return(DOS_FALSE);
- parentkey = block->db_Parent;
- hashval = hash(&block->db_Name[1], block->db_Name[0]);
- nextkey = block->db_HashChain;
-
-
- /* Now see if we can find the 'to' file. It shouldn't exist, except */
- /* if we are only using rename to change the case of the name. */
- len = *toname++;
- if (!(dirkey = FindDir(global, tokey, &toname, &len)))
- {
- global->pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND; /* or something.. */
- return(DOS_FALSE);
- }
- if(tokey = FindEntry(global, dirkey, toname, len))
- /* check this is not same file name with just case changed */
- if (tokey != fromkey)
- {
- global->pkt->dp_Res2 = ERROR_OBJECT_EXISTS;
- return(DOS_FALSE);
- }
-
- /* Check to see if we're trying to rename an ancestor to a */
- /* descendant, which has the unfortunate effect of orphaning it. */
- /* Can save some thrashing if source & dest are in same directory */
- if (dirkey != parentkey)
- {
- ancestor = dirkey;
- BUG(("RenameEntry: Ancestor = %d\n", ancestor));
- while (ancestor)
- {
- if (ancestor == fromkey)
- {
- global->pkt->dp_Res2 = ERROR_OBJECT_IN_USE; /* Better ideas? */
- return(DOS_FALSE);
- }
- if ((block = (struct DirBlock *)GetBlock(global, ancestor)) == NULL)
- /* haven't located anything oedipal, nothing can be wrong, can */
- /* be wrong, can be wrong... */
- break;
- ancestor = block->db_Parent;
- }
- BUG(("RenameEntry: Root = %d\n", ancestor));
- }
-
- /* Now ready to unlink the 'from' entry from its directory. */
-
- BUG(("RenameEntry: parentkey=%d, prevkey=%d, nextkey=%d\n",
- parentkey, prevkey, nextkey));
-
- if (prevkey)
- {
- if ((block = (struct DirBlock *)ModBlock(global, prevkey))
- == NULL)
- return(DOS_FALSE);
- block->db_HashChain = nextkey;
- }
- else
- {
- if ((block = (struct DirBlock *)ModBlock(global, parentkey)) == NULL)
- return(DOS_FALSE);
- BUG((" hashval = %d\n", hashval));
- block->db_HashTable[hashval] = nextkey;
- }
-
- /* The disk seems to be writable - let's hope it stays that way */
-
- /* Now link into the new directory under the new name */
- nextkey = LinkDir(global, dirkey, fromkey, hash(toname, len));
- if (nextkey == -1)
- {
- /* Relink from file back into from directory and return. */
- if ((nextkey = LinkDir(global, parentkey, fromkey, hashval)) == -1)
- /* How embarrasing! Still, with the checks we did earlier, this */
- /* is definitely not likely to happen (I think...) */
- return(DOS_FALSE);
- if ((block = (struct DirBlock *)ModBlock(global, fromkey)) == NULL)
- return(DOS_FALSE);
- block->db_HashChain = nextkey;
- return(DOS_FALSE); /* but we maintain our dignity */
- }
-
- /* if this next bit fails, we've screwed up the new directory... */
- if ((block = (struct DirBlock *)ModBlock(global, fromkey)) == NULL)
- return(DOS_FALSE); /* hope ModBlock set a good error in Res2 */
- block->db_HashChain = nextkey; /* complete fwd link in directory */
- block->db_Parent = dirkey;
- memcpy(&block->db_Name[1], toname, len);
- block->db_Name[0] = len;
- BUG(("RenameEntry: Entry %d linked to directory %d\n", fromkey, dirkey));
- return(DOS_TRUE);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* Routine: LinkDir */
- /* Purpose: link a block into a directory (almost - for logistic reasons, */
- /* caller must fill return value into his own block->db_HashChain)*/
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- KEY LinkDir(global, parentkey, filekey, hashval)
- GLOBAL global;
- KEY parentkey, filekey;
- int hashval;
- {
- struct DirBlock *block;
- KEY nextkey;
-
- block = (struct DirBlock *)ModBlock(global, parentkey);
- if (block == NULL)
- return(-1); /* not a nice key */
-
- SetDateInfo(global, block); /* timestamp the change in the parent dir */
- BUG(("LinkDir: Mod block %ld at %08lx newkey = %ld\n",
- parentkey, block, filekey));
-
- /* Enter the key into the list in a sorted fashion. The lowest key must */
- /* appear first. */
- nextkey = block->db_HashTable[hashval];
- if (nextkey == 0 || filekey < nextkey)
- {
- /* it goes at the head of the chain, so we can simply put it there */
- block->db_HashTable[hashval] = filekey;
- }
- else
- {
- while(1)
- {
- /* Not at the head of the chain. We need to find where it goes on */
- /* the chain. First we get the next block in the chain and see */
- /* what it links to. */
- if ((block = (struct DirBlock *)GetBlock(global, nextkey)) == NULL)
- return(-1); /* the bad news key */
- /* Should we go after this block ? */
- if (block->db_HashChain == 0 ||
- block->db_HashChain > filekey)
- {
- /* Yes, make sure we can modify this block */
- if ((block = (struct DirBlock *)ModBlock(global, nextkey)) == NULL)
- return(-1); /* this'll slay them */
- /* Insert us in the chain and stop the search */
- nextkey = block->db_HashChain;
- block->db_HashChain = filekey;
- break;
- }
- /* advance search */
- nextkey = block->db_HashChain;
- }
- }
- /* if we got here we done good */
- return(nextkey); /* note 0 is a healthy value here: end of the line */
- }
-