home *** CD-ROM | disk | FTP | other *** search
- /*
- (C) 1995-96 AROS - The Amiga Replacement OS
- $Id: ffs_handler.c,v 1.4 1997/01/27 00:22:40 ldp Exp $
- $Log: ffs_handler.c,v $
- Revision 1.4 1997/01/27 00:22:40 ldp
- Include proto instead of clib
-
- Revision 1.3 1996/12/10 13:59:49 aros
- Moved #include into first column to allow makedepend to see it.
-
- Revision 1.2 1996/11/22 12:29:01 aros
- More complete filesystem: Readonly and makedir.
-
- Desc:
- Lang:
- */
- #include <devices/trackdisk.h>
- #include <exec/errors.h>
- #include <exec/types.h>
- #include <exec/resident.h>
- #include <exec/memory.h>
- #include <exec/semaphores.h>
- #include <proto/exec.h>
- #include <utility/tagitem.h>
- #include <proto/utility.h>
- #include <dos/dosextens.h>
- #include <dos/dosasl.h>
- #include <dos/exall.h>
- #include <dos/filesystem.h>
- #include <proto/dos.h>
- #include <aros/libcall.h>
- #include <aros/machine.h>
- #ifdef __GNUC__
- #include "ffs_handler_gcc.h"
- #endif
- #include <stddef.h>
-
- /*
- * The amiga (fast) filing system:
- *
- * Unlike some Un*x filesystems the amiga ffs is not split into a fixed inode
- * and data section but instead the inode information is scattered across
- * the entire disk. Each "inode" lives in it's own disk block (usually near
- * the rest of the file) containing enough information to recover the entire
- * file including name, parent directory, creation date and protection bits.
- *
- * The root directory block can be found in the middle of the partition.
- * It contains a hashtable pointing to chained linear lists of file header
- * or further (user) directory blocks. A file header block points to a
- * number of simple data blocks and a list of further file list blocks
- * containing pointers to data blocks.
- *
- * data blocks in the old amiga filing system consist of a small header
- * and the data. data blocks in the fast filing system just consist of
- * the stale data.
- */
-
- /* All information in the amiga FS is big endian */
-
- #if BIG_ENDIAN
- #define EC(a) (a)
- #else
- #define EC(a) (((a)>>24)|(((a)&0xff0000)>>8)|(((a)&0xff00)<<8)|((a)<<24))
- #endif
-
- /*
- * Structure describing a single block of the amiga filesystem. The
- * fb_hashtable field in the middle of the structure is sized so that
- * the entire structure fills a complete block. Therefore all following fields
- * don't live at a fixed offset and are just defines with HASHSIZE being
- * the number of hashtable entries.
- */
-
- struct filesysblock
- {
- ULONG fb_type; /* block types (see below) */
- ULONG fb_own; /* own block number */
- ULONG fb_blocks; /* the number of blocks in the file */
- ULONG fb_hashsize; /* size of the hashtable */
- ULONG fb_firstdata; /* first data block */
- ULONG fb_chksum; /* sums the block to 0 */
- ULONG fb_hashtable[122]; /* blocknumbers of blocksize/4-56 blocks */
- #define fb_data /* data for data blocks, data block numbers else */ fb_hashtable
- #define fb_validated /* ~0: disk is validated */ fb_hashtable[HASHSIZE]
- #define fb_bam /* 25 block allocation map blocks */ fb_hashtable+HASHSIZE+1
- #define fb_bam_extend /* first bam extend block */ fb_hashtable[HASHSIZE+26]
- #define fb_days /* modification date... */ fb_hashtable[HASHSIZE+27]
- #define fb_mins /* ...and time... */ fb_hashtable[HASHSIZE+28]
- #define fb_ticks /* ...dito */ fb_hashtable[HASHSIZE+29]
- #define fb_name /* file/disk/dir name */ fb_hashtable+HASHSIZE+30
- #define fb_lastlink /* chained links to file/dir */ fb_hashtable[HASHSIZE+38]
- #define fb_nextlink fb_hashtable[HASHSIZE+39]
- #define fb_vdays /* volume altered time */ fb_hashtable[HASHSIZE+40]
- #define fb_vmins fb_hashtable[HASHSIZE+41]
- #define fb_vticks fb_hashtable[HASHSIZE+42]
- #define fb_cdays /* volume creation time */ fb_hashtable[HASHSIZE+43]
- #define fb_cmins fb_hashtable[HASHSIZE+44]
- #define fb_cticks fb_hashtable[HASHSIZE+45]
- #define fb_nexthash /* next hash chain entry */ fb_hashtable[HASHSIZE+46]
- #define fb_parent /* parent directory */ fb_hashtable[HASHSIZE+47]
- #define fb_extend /* next file list block */ fb_hashtable[HASHSIZE+48]
- #define fb_sectype /* secondary type */ fb_hashtable[HASHSIZE+49]
- #define fb_owner /* UID<<16+GID */ fb_hashtable[HASHSIZE+1]
- #define fb_protect /* protection bits^0xf */ fb_hashtable[HASHSIZE+2]
- #define fb_size /* size of the file in bytes */ fb_hashtable[HASHSIZE+3]
- #define fb_comment /* comment */ fb_hashtable+HASHSIZE+4
- #define fb_id /* filesystem magic number */ fb_type
- };
-
- /* Block types */
- #define BT_STRUCT 2 /* describes the structure of the filesystem */
- #define BT_DATA 8 /* file data block */
- #define BT_FILELIST 16 /* file list block */
-
- /* Secondary types (see dos/dosextens.h) */
- #if 0
- #define ST_ROOT 1 /* Root directory */
- #define ST_USERDIR 2 /* Normal directory */
- #define ST_FILE -3 /* file header/list block */
- #endif
-
- #define HASHSIZE dev->hashsize
-
- #define NEWLIST(l) \
- ((l)->lh_Head=(struct Node *)&(l)->lh_Tail, \
- (l)->lh_Tail=NULL, \
- (l)->lh_TailPred=(struct Node *)(l))
-
- extern const char name[];
- extern const char version[];
- extern const APTR inittabl[4];
- extern void *const functable[];
- extern const UBYTE datatable;
- extern struct ffsbase *AROS_SLIB_ENTRY(init,ffsdev)();
- extern void AROS_SLIB_ENTRY(open,ffsdev)();
- extern BPTR AROS_SLIB_ENTRY(close,ffsdev)();
- extern BPTR AROS_SLIB_ENTRY(expunge,ffsdev)();
- extern int AROS_SLIB_ENTRY(null,ffsdev)();
- extern void AROS_SLIB_ENTRY(beginio,ffsdev)();
- extern LONG AROS_SLIB_ENTRY(abortio,ffsdev)();
- extern void deventry();
- extern const char end;
-
- /* Structure describing a cache block */
- struct cinfo
- {
- ULONG lastacc; /* time index for LRU cache */
- ULONG num; /* blocknumber of this block (-1: invalid) */
- struct filesysblock *data; /* Pointer to block */
- LONG synced; /* 0: needs to be written */
- };
-
- /* Device node: one mounted drive */
- struct dev
- {
- struct MinNode node;
- ULONG numbuffers; /* number of buffers */
- UBYTE *cache; /* cached blocks (contiguous to allow
- * reading of more than one buffer per
- * device access). */
- struct cinfo *cinfos; /* array of cinfo structures */
- struct IOExtTD *iotd; /* I/O request for this device */
- ULONG accindex; /* actual access index */
- struct vol *vol; /* Pointer to volume node */
- LONG error; /* ERROR_NO_DISK, ERROR_NOT_A_DOS_DISK or 0 */
-
- /* Describing the partition */
- ULONG poffset; /* number of the first partition block */
- ULONG psize; /* number of blocks of this partition */
- ULONG reserved; /* Reserved blocks */
- ULONG bsize; /* size of the blocks */
- ULONG rnum; /* number of the root block */
- ULONG hashsize; /* number of hashtable entries */
- struct fh *fh; /* Device handle */
-
- ULONG bmext; /* current bitmap extend block */
- ULONG fblock; /* first free block */
- };
-
- /* Volume node: one mounted disk */
- struct vol
- {
- struct MinNode node;
- struct dev *dev; /* drive where the disk is inserted or NULL */
- struct MinList files; /* All filehandles for this disk */
- struct MinList dirs; /* All directory handles */
-
- /* Describing the partition */
- ULONG psize; /* See above */
- ULONG reserved;
- ULONG bsize;
- ULONG rnum;
- struct DosList *dlist; /* pointer to dos list entry */
-
- ULONG cdays, cmins, cticks;
- ULONG vdays, vmins, vticks;
-
- ULONG id; /* filesystem type */
- };
-
- /* A handle for a device, file or directory */
- struct fh
- {
- struct MinNode node;
- struct vol *vol; /* Volume or device node */
- ULONG block; /* FIB or 0 for device handles */
- LONG locked; /* Object is locked */
- /* actual Seek position */
- ULONG current; /* actual FIB for dirs, block for files */
- ULONG blocknr; /* the Nth block in the file */
- ULONG index; /* Hash chain# for dirs, the Nth byte in the block for files */
- };
-
- int entry(void)
- {
- /* If the device was executed by accident return error code. */
- return -1;
- }
-
- const struct Resident resident=
- {
- RTC_MATCHWORD,
- (struct Resident *)&resident,
- (APTR)&end,
- RTF_AUTOINIT,
- 1,
- NT_LIBRARY,
- 0,
- (char *)name,
- (char *)&version[6],
- (ULONG *)inittabl
- };
-
- const char name[]="ffs.handler";
-
- const char version[]="$VER: ffs handler 1.0 (28.3.96)\n\015";
-
- const APTR inittabl[4]=
- {
- (APTR)sizeof(struct ffsbase),
- (APTR)functable,
- (APTR)&datatable,
- &AROS_SLIB_ENTRY(init,ffsdev)
- };
-
- void *const functable[]=
- {
- &AROS_SLIB_ENTRY(open,ffsdev),
- &AROS_SLIB_ENTRY(close,ffsdev),
- &AROS_SLIB_ENTRY(expunge,ffsdev),
- &AROS_SLIB_ENTRY(null,ffsdev),
- &AROS_SLIB_ENTRY(beginio,ffsdev),
- &AROS_SLIB_ENTRY(abortio,ffsdev),
- (void *)-1
- };
-
- const UBYTE datatable=0;
-
- #undef SysBase
- struct ExecBase *SysBase;
-
- AROS_LH2(struct ffsbase *, init,
- AROS_LHA(struct ffsbase *, ffsbase, D0),
- AROS_LHA(BPTR, segList, A0),
- struct ExecBase *, sysbase, 0, ffsdev)
- {
- AROS_LIBFUNC_INIT
-
- /* This function is single-threaded by exec by calling Forbid. */
-
- struct Task *task;
- APTR stack;
-
- /* Store arguments */
- SysBase=sysbase;
- ffsbase->seglist=segList;
- NEWLIST((struct List *)&ffsbase->inserted);
- NEWLIST((struct List *)&ffsbase->mounted);
- NEWLIST((struct List *)&ffsbase->removed);
- DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",39);
- if(DOSBase!=NULL)
- {
- NEWLIST(&ffsbase->port.mp_MsgList);
- ffsbase->port.mp_Node.ln_Type=NT_MSGPORT;
- ffsbase->port.mp_Flags=PA_IGNORE;
- NEWLIST(&ffsbase->dport.mp_MsgList);
- ffsbase->dport.mp_Node.ln_Type=NT_MSGPORT;
- ffsbase->dport.mp_Flags=PA_IGNORE;
- NEWLIST(&ffsbase->rport.mp_MsgList);
- ffsbase->rport.mp_Node.ln_Type=NT_MSGPORT;
- ffsbase->rport.mp_Flags=PA_SIGNAL;
- ffsbase->rport.mp_SigBit=SIGB_SINGLE;
- InitSemaphore(&ffsbase->sigsem);
-
- task=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
- if(task!=NULL)
- {
- ffsbase->port.mp_SigTask=task;
- ffsbase->dport.mp_SigTask=task;
- NEWLIST(&task->tc_MemEntry);
- task->tc_Node.ln_Type=NT_TASK;
- task->tc_Node.ln_Name="ffs.handler task";
-
- stack=AllocMem(2048,MEMF_PUBLIC);
- if(stack!=NULL)
- {
- task->tc_SPLower=stack;
- task->tc_SPUpper=(BYTE *)stack+2048;
- #if AROS_STACK_GROWS_DOWNWARDS
- task->tc_SPReg=(BYTE *)task->tc_SPUpper-SP_OFFSET-sizeof(APTR);
- ((APTR *)task->tc_SPUpper)[-1]=ffsbase;
- #else
- task->tc_SPReg=(BYTE *)task->tc_SPLower-SP_OFFSET+sizeof(APTR);
- *(APTR *)task->tc_SPLower=ffsbase;
- #endif
-
- if(AddTask(task,deventry,NULL)!=NULL)
- return ffsbase;
-
- FreeMem(stack,2048);
- }
- FreeMem(task,sizeof(struct Task));
- }
- CloseLibrary((struct Library *)DOSBase);
- }
-
- return NULL;
- AROS_LIBFUNC_EXIT
- }
-
- AROS_LH3(void, open,
- AROS_LHA(struct IOFileSys *, iofs, A1),
- AROS_LHA(ULONG, unitnum, D0),
- AROS_LHA(ULONG, flags, D1),
- struct ffsbase *, ffsbase, 1, ffsdev)
- {
- AROS_LIBFUNC_INIT
-
- /* Keep compiler happy */
- unitnum=flags=0;
-
- /* I have one more opener. */
- ffsbase->device.dd_Library.lib_OpenCnt++;
-
- /* Send message to device task */
- ObtainSemaphore(&ffsbase->sigsem);
- ffsbase->rport.mp_SigTask=FindTask(NULL);
- iofs->IOFS.io_Command=-1;
- PutMsg(&ffsbase->port,&iofs->IOFS.io_Message);
- WaitPort(&ffsbase->rport);
- (void)GetMsg(&ffsbase->rport);
- ReleaseSemaphore(&ffsbase->sigsem);
-
- if(!iofs->io_DosError)
- {
- iofs->IOFS.io_Error=0;
- ffsbase->device.dd_Library.lib_Flags&=~LIBF_DELEXP;
- return;
- }
-
- /* set secondary error code and return */
- iofs->IOFS.io_Error=IOERR_OPENFAIL;
- ffsbase->device.dd_Library.lib_OpenCnt--;
-
- AROS_LIBFUNC_EXIT
- }
-
- AROS_LH1(BPTR, close,
- AROS_LHA(struct IOFileSys *, iofs, A1),
- struct ffsbase *, ffsbase, 2, ffsdev)
- {
- AROS_LIBFUNC_INIT
- /*
- This function is single-threaded by exec by calling Forbid.
- If you break the Forbid() another task may enter this function
- at the same time. Take care.
- */
-
- /* Send message to device task */
- ObtainSemaphore(&ffsbase->sigsem);
- ffsbase->rport.mp_SigTask=FindTask(NULL);
- iofs->IOFS.io_Command=-2;
- PutMsg(&ffsbase->port,&iofs->IOFS.io_Message);
- WaitPort(&ffsbase->rport);
- ReleaseSemaphore(&ffsbase->sigsem);
-
- if(iofs->io_DosError)
- return 0;
-
- /* Let any following attemps to use the device crash hard. */
- iofs->IOFS.io_Device=(struct Device *)-1;
-
- /* I have one fewer opener. */
- if(!--ffsbase->device.dd_Library.lib_OpenCnt)
- {
- /* Delayed expunge pending? */
- if(ffsbase->device.dd_Library.lib_Flags&LIBF_DELEXP)
- /* Then expunge the device */
- return expunge();
- }
- return 0;
- AROS_LIBFUNC_EXIT
- }
-
- AROS_LH0(BPTR, expunge, struct ffsbase *, ffsbase, 3, ffsdev)
- {
- AROS_LIBFUNC_INIT
-
- BPTR ret;
- /*
- This function is single-threaded by exec by calling Forbid.
- Never break the Forbid() or strange things might happen.
- */
-
- /* Test for openers. */
- if(ffsbase->device.dd_Library.lib_OpenCnt)
- {
- /* Set the delayed expunge flag and return. */
- ffsbase->device.dd_Library.lib_Flags|=LIBF_DELEXP;
- return 0;
- }
-
- /* Kill device task and free all resources */
- RemTask(ffsbase->port.mp_SigTask);
- FreeMem(((struct Task *)ffsbase->port.mp_SigTask)->tc_SPLower,2048);
- FreeMem(ffsbase->port.mp_SigTask,sizeof(struct Task));
- CloseLibrary((struct Library *)ffsbase->dosbase);
-
- /* Get rid of the device. Remove it from the list. */
- Remove(&ffsbase->device.dd_Library.lib_Node);
-
- /* Get returncode here - FreeMem() will destroy the field. */
- ret=ffsbase->seglist;
-
- /* Free the memory. */
- FreeMem((char *)ffsbase-ffsbase->device.dd_Library.lib_NegSize,
- ffsbase->device.dd_Library.lib_NegSize+ffsbase->device.dd_Library.lib_PosSize);
-
- return ret;
- AROS_LIBFUNC_EXIT
- }
-
- AROS_LH0I(int, null, struct ffsbase *, ffsbase, 4, ffsdev)
- {
- AROS_LIBFUNC_INIT
- return 0;
- AROS_LIBFUNC_EXIT
- }
-
- AROS_LH1(void, beginio,
- AROS_LHA(struct IOFileSys *, iofs, A1),
- struct ffsbase *, ffsbase, 5, ffsdev)
- {
- AROS_LIBFUNC_INIT
-
- /* Nothing is done quick */
- iofs->IOFS.io_Flags&=~IOF_QUICK;
-
- /* So let the device task do it */
- PutMsg(&ffsbase->port,&iofs->IOFS.io_Message);
-
- AROS_LIBFUNC_EXIT
- }
-
- AROS_LH1(LONG, abortio,
- AROS_LHA(struct IOFileSys *, iofs, A1),
- struct ffsbase *, ffsbase, 6, ffsdev)
- {
- AROS_LIBFUNC_INIT
- return 0;
- AROS_LIBFUNC_EXIT
- }
-
- #define touch_read(dev,cinfo) ((cinfo)->lastacc=((dev)->accindex)++)
- #define touch_write(dev,cinfo) ((cinfo)->lastacc=((dev)->accindex)++,(cinfo)->synced=0)
-
- static LONG write_block(struct ffsbase *ffsbase, struct dev *dev, struct cinfo *cinfo)
- {
- cinfo->synced=1;
- dev->iotd->iotd_Req.io_Command=CMD_WRITE;
- dev->iotd->iotd_Req.io_Data =cinfo->data;
- dev->iotd->iotd_Req.io_Offset =(dev->poffset+cinfo->num)*dev->bsize;
- dev->iotd->iotd_Req.io_Length =dev->bsize;
- return DoIO((struct IORequest *)dev->iotd);
- }
-
- static LONG get_buffer(struct ffsbase *ffsbase, struct dev *dev, struct cinfo **cinfo)
- {
- LONG ret=0;
- struct cinfo *buf;
- ULONG max,i;
- buf=dev->cinfos;
- max=dev->accindex-buf->lastacc;
- for(i=1;i<dev->numbuffers;i++)
- if(dev->accindex-dev->cinfos[i].lastacc>max)
- {
- buf=&dev->cinfos[i];
- max=dev->accindex-buf->lastacc;
- }
- if(!buf->synced)
- ret=write_block(ffsbase,dev,buf);
- *cinfo=buf;
- return ret;
- }
-
- LONG get_block(struct ffsbase *ffsbase, struct dev *dev, struct cinfo **cinfo, ULONG num)
- {
- ULONG i;
- int ret;
- if(dev==NULL)
- return ERROR_DEVICE_NOT_MOUNTED;
- for(i=0;i<dev->numbuffers;i++)
- if(dev->cinfos[i].num==num)
- {
- *cinfo=&dev->cinfos[i];
- return 0;
- }
- ret=get_buffer(ffsbase,dev,cinfo);
- if(ret)
- return ret;
- (*cinfo)->num=~0;
- (*cinfo)->synced=0;
- dev->iotd->iotd_Req.io_Command=CMD_READ;
- dev->iotd->iotd_Req.io_Data =(*cinfo)->data;
- dev->iotd->iotd_Req.io_Offset =(dev->poffset+num)*dev->bsize;
- dev->iotd->iotd_Req.io_Length =dev->bsize;
- ret=DoIO((struct IORequest *)dev->iotd);
- if(ret)
- return 1; /* I/O Error */
- (*cinfo)->num=num;
- (*cinfo)->synced=1;
- return 0;
- }
-
- ULONG checksum(struct dev *dev, struct cinfo *cinfo)
- {
- ULONG i;
- #if AROS_BIG_ENDIAN
- ULONG *p=(ULONG *)cinfo->data, sum=0;
- for(i=0;i<dev->bsize/4;i++)
- sum+=*p++;
- return -sum;
- #else
- UBYTE *p=(UBYTE *)cinfo->data;
- ULONG s1=0, s2=0, s3=0, s4=0;
- for(i=0;i<dev->bsize/4;i++)
- s1+=*p++, s2+=*p++, s3+=*p++, s4+=*p++;
- return -(((s1*256+s2)*256+s3)*256+s4);
- #endif
- }
-
- LONG read_block_chk(struct ffsbase *ffsbase, struct dev *dev, struct cinfo **cinfo, ULONG num)
- {
- int ret;
- ret=get_block(ffsbase,dev,cinfo,num);
- if(ret)
- return ret;
- if(checksum(dev,*cinfo))
- {KPrintF("%s\n",(*cinfo)->data->fb_name);
- return ERROR_BAD_NUMBER; /* Checksum error */}
- return 0;
- }
-
- void dump(struct ffsbase *ffsbase, struct cinfo *block)
- {
- int i;
- for(i=0;i<128;i++)
- KPrintF("%lx ",EC(((ULONG *)block->data)[i]));
- KPrintF("\n");
- }
-
- static LONG alloc_block(struct ffsbase *ffsbase, struct dev *dev, ULONG *newblk)
- {
- struct cinfo *block;
- ULONG a, b;
- ULONG i, imax, k, kmax, kmax2;
- ULONG bpb, bblock, btotal, next;
- LONG error;
-
- bpb=8*(dev->bsize-4);
- bblock=dev->fblock/bpb;
- btotal=(dev->psize-dev->reserved+bpb-1)/bpb;
- k=1+(dev->fblock%bpb)/32;
- for(;;)
- {
- if(bblock<25)
- {
- i=7+HASHSIZE+bblock;
- imax=7+25+HASHSIZE;
- }else
- {
- i=(bblock-25)%(dev->bsize/4-1);
- imax=dev->bsize/4-1;
- }
- for(;i<imax;i++)
- {
- if(bblock>=btotal)
- return ERROR_DISK_FULL;
- if(bblock<25)
- error=read_block_chk(ffsbase,dev,&block,dev->bmext);
- else
- error=get_block(ffsbase,dev,&block,dev->bmext);
- if(error)
- return error;
- next=EC(((ULONG *)block->data)[imax]);
- touch_read(dev,block);
- error=read_block_chk(ffsbase,dev,&block,EC(((ULONG *)block->data)[i]));
- if(error)
- return error;
- kmax=dev->bsize/4;
- kmax2=1+(dev->psize-dev->reserved-bblock*bpb+31)/32;
- if(kmax>kmax2)
- kmax=kmax2;
- touch_read(dev,block);
- for(;k<kmax;k++)
- if(((ULONG *)block->data)[k])
- {
- a=EC(((ULONG *)block->data)[k]);
- b=a&-a;
- a&=~b;
- b=(b&0xffff0000?16:0)+(b&0xff00ff00?8:0)+(b&0xf0f0f0f0?4:0)+
- (b&0xcccccccc?2:0) +(b&0xaaaaaaaa?1:0);
- dev->fblock=bblock*bpb+(k-1)*32+b;
- if(dev->fblock+dev->reserved>=dev->psize)
- return ERROR_DISK_FULL;
- *newblk=dev->fblock+dev->reserved;
- ((ULONG *)block->data)[k]=EC(a);
- *(ULONG *)block->data=0;
- a=checksum(dev,block);
- *(ULONG *)block->data=EC(a);
- touch_write(dev,block);
- return 0;
- }
- bblock++;
- dev->fblock=bblock*bpb;
- k=1;
- }
- dev->bmext=next;
- }
- }
-
- static LONG free_block(struct ffsbase *ffsbase, struct dev *dev, ULONG blk)
- {
- struct cinfo *block;
- ULONG a, k, old, oldbblock, bpb, bblock, btotal, next;
- LONG error;
-
- bpb=8*(dev->bsize-4);
- oldbblock=dev->fblock/bpb;
- btotal=(dev->psize-dev->reserved+bpb-1)/bpb;
- bblock=blk/bpb;
- k=blk%bpb;
- if(bblock<oldbblock)
- {
- dev->bmext=dev->rnum;
- if(bblock>25)
- {
- error=read_block_chk(ffsbase,dev,&block,dev->bmext);
- if(error)
- return error;
- dev->bmext=EC(((ULONG *)block->data)[7+25+HASHSIZE]);
- touch_read(dev,block);
- old=(old-25)/(dev->bsize/4-1);
- while(old--)
- {
- error=get_block(ffsbase,dev,&block,dev->bmext);
- if(error)
- return error;
- dev->bmext=EC(((ULONG *)block->data)[dev->bsize/4-1]);
- touch_read(dev,block);
- }
- }
- }
- if(dev->fblock>blk)
- dev->fblock=blk;
- if(bblock<25)
- {
- error=read_block_chk(ffsbase,dev,&block,dev->bmext);
- next=EC(((ULONG *)block->data)[7+HASHSIZE+bblock]);
- }else
- {
- error=get_block(ffsbase,dev,&block,dev->bmext);
- next=EC(((ULONG *)block->data)[(bblock-25)%(dev->bsize/4-1)]);
- }
- if(error)
- return error;
- touch_read(dev,block);
- error=read_block_chk(ffsbase,dev,&block,next);
- if(error)
- return error;
- a=EC(((ULONG *)block->data)[k/32+1]);
- a|=1<<(k&31);
- ((ULONG *)block->data)[k/32+1]=EC(a);
- touch_write(dev,block);
- return 0;
- }
-
- static void zerofill(UBYTE *address, ULONG size)
- {
- while(size--)
- *address++=0;
- }
-
- LONG mount(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, LONG unit, IPTR *envec)
- {
- struct dev *dev;
- ULONG i,tracksize;
- dev=(struct dev *)AllocMem(sizeof(struct dev),MEMF_CLEAR);
- if(dev!=NULL)
- {
- dev->fh=(struct fh *)AllocMem(sizeof(struct fh),MEMF_CLEAR);
- if(dev->fh!=NULL)
- {
- dev->fh->vol=(struct vol *)dev;
- dev->cache=(UBYTE *)AllocMem(envec[DE_NUMBUFFERS]*envec[DE_BLOCKSIZE],MEMF_CLEAR);
- if(dev->cache!=NULL)
- {
- dev->cinfos=(struct cinfo *)AllocMem(sizeof(struct cinfo)*envec[DE_NUMBUFFERS],MEMF_CLEAR);
- if(dev->cinfos!=NULL)
- {
- for(i=0;i<envec[DE_NUMBUFFERS];i++)
- {
- dev->cinfos[i].data=(struct filesysblock *)&dev->cache[envec[DE_BLOCKSIZE]*i];
- dev->cinfos[i].num=-1;
- dev->cinfos[i].synced=1;
- }
- tracksize=envec[DE_NUMHEADS]*envec[DE_BLKSPERTRACK];
- dev->numbuffers=envec[DE_NUMBUFFERS];
- dev->poffset=tracksize*envec[DE_LOWCYL];
- dev->psize=tracksize*(envec[DE_HIGHCYL]-envec[DE_LOWCYL]+1);
- dev->reserved=envec[DE_RESERVEDBLKS];
- dev->bsize=envec[DE_BLOCKSIZE];
- dev->rnum=(dev->psize-dev->reserved-1)/2+dev->reserved;
- dev->hashsize=(dev->bsize-224)/4;
- dev->iotd=(struct IOExtTD *)CreateIORequest(&ffsbase->dport,sizeof(struct IOExtTD));
- if(dev->iotd!=NULL)
- {
- if(!OpenDevice(name,unit,(struct IORequest *)dev->iotd,0))
- {
- *fh=dev->fh;
- return 0;
- }
- DeleteIORequest((struct IORequest *)dev->iotd);
- }
- FreeMem(dev->cinfos,sizeof(struct cinfo)*envec[DE_NUMBUFFERS]);
- }
- FreeMem(dev->cache,envec[DE_NUMBUFFERS]*envec[DE_BLOCKSIZE]);
- }
- FreeMem(dev->fh,sizeof(struct fh));
- }
- FreeMem(dev,sizeof(struct dev));
- }
- return ERROR_NO_FREE_STORE;
- }
-
- void flush(struct dev *dev)
- {
- ULONG i;
- for(i=0;i<dev->numbuffers;i++)
- {
- dev->cinfos[i].num=-1;
- dev->cinfos[i].synced=1;
- }
- }
-
- LONG disk_change(struct ffsbase *ffsbase, struct dev *dev)
- {
- struct cinfo *root, *boot;
- ULONG id;
- LONG error;
- struct vol *vol;
- struct fh *fh;
- flush(dev);
- error=get_block(ffsbase,dev,&boot,0);
- if(error)
- return dev->error=error;
- id=EC(boot->data->fb_id);
- if(id!=ID_DOS_DISK&&id!=ID_FFS_DISK)
- return dev->error=ERROR_NOT_A_DOS_DISK;
- error=read_block_chk(ffsbase,dev,&root,dev->rnum);
- if(error==ERROR_BAD_NUMBER||EC(root->data->fb_hashsize)!=dev->hashsize||
- root->data->fb_type!=EC(BT_STRUCT)||root->data->fb_sectype!=EC(ST_ROOT)||
- root->data->fb_validated!=EC(~0ul))
- return dev->error=ERROR_NOT_A_DOS_DISK;
- #if 0
- for(dev=ffsbase->volumes.mlh_Head;
- dev->node.mln_Succ!=NULL;
- dev=dev->node.mln_Succ)
- if(dev->cdays ==root->data->fb_cdays &&
- dev->cmins ==root->data->fb_cmins &&
- dev->cticks==root->data->fb_cticks&&
- dev->vdays ==root->data->fb_vdays &&
- dev->vmins ==root->data->fb_vmins &&
- dev->vticks==root->data->fb_vticks&&
- {
- }
- #endif
- vol=AllocMem(sizeof(struct vol),MEMF_PUBLIC);
- if(vol!=NULL)
- {
- fh=AllocMem(sizeof(struct fh),MEMF_CLEAR);
- if(fh!=NULL)
- {
- UBYTE buf[32];
- ULONG l;
- fh->vol =vol;
- fh->block=dev->rnum;
- vol->id =id;
- vol->bsize =dev->bsize;
- vol->psize =dev->psize;
- vol->reserved=dev->reserved;
- vol->cdays =EC(root->data->fb_cdays);
- vol->cmins =EC(root->data->fb_cmins);
- vol->cticks=EC(root->data->fb_cticks);
- vol->vdays =EC(root->data->fb_vdays);
- vol->vmins =EC(root->data->fb_vmins);
- vol->vticks=EC(root->data->fb_vticks);
- NEWLIST((struct List *)&vol->files);
- NEWLIST((struct List *)&vol->dirs);
- l=*(UBYTE *)(root->data->fb_name);
- if(l<31)
- {
- buf[l]=0;
- CopyMem((STRPTR)(root->data->fb_name)+1,buf,l);
- vol->dlist=MakeDosEntry(buf,DLT_VOLUME);
- if(vol->dlist!=NULL)
- {
- vol->dlist->dol_Device=&ffsbase->device;
- vol->dlist->dol_Unit=(struct Unit *)fh;
- dev->vol=vol;
- vol->dev=dev;
- dev->bmext=dev->rnum;
- dev->fblock=0;
- AddTail((struct List *)&ffsbase->inserted,(struct Node *)vol);
- ffsbase->dlflag=1;
- return 0;
- }
- }
- FreeMem(fh,sizeof(struct fh));
- }
- FreeMem(dev,sizeof(struct dev));
- }
- return ERROR_NO_FREE_STORE;
- }
-
- #define toupper_ffs(c) ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c))
-
- static int namechk(struct dev *dev, struct cinfo *cur, STRPTR name)
- {
- STRPTR s1=(STRPTR)(cur->data->fb_name);
- ULONG l=*s1++;
- if(l)
- do
- {
- if(toupper_ffs(*s1)!=toupper_ffs(*name)||*name=='/')
- return 1;
- s1++, name++;
- }
- while(--l);
- return *name;
- }
-
- static void setname(struct dev *dev, struct cinfo *block, STRPTR name)
- {
- STRPTR s1=(STRPTR)(block->data->fb_name)+1;
- ULONG l;
- for(l=0;l<30;l++)
- {
- if(!*name)
- break;
- *s1++=*name++;
- }
- *(STRPTR)(block->data->fb_name)=l;
- for(;l<31;l++)
- *s1++=0;
- }
-
- static ULONG hash(struct dev *dev, STRPTR name)
- {
- ULONG l, h=0;
- STRPTR s2=name;
- while(*s2&&*s2!='/')
- s2++;
- l=s2-name>30?30:s2-name;
- h=l;
- while(l--)
- {
- h=(h*13+toupper_ffs(*name))&0x7ff;
- name++;
- }
- return h%HASHSIZE;
- }
-
- static LONG findname(struct ffsbase *ffsbase, struct fh *fh, STRPTR *name, struct cinfo **dir)
- {
- LONG error;
- struct cinfo *cur=*dir;
- char *rest=*name;
- ULONG block;
- struct dev *dev;
-
- block=fh->block;
- if(!block)
- {
- dev=(struct dev *)fh->vol;
- block=dev->rnum;
- }else
- dev=fh->vol->dev;
- error=read_block_chk(ffsbase,dev,&cur,block);
- if(error)
- return error;
-
- while(*rest)
- {
- touch_read(dev,cur);
- if(*rest=='/')
- {
- if(cur->data->fb_sectype==EC(ST_ROOT))
- {
- *name=rest;
- *dir=cur;
- return ERROR_OBJECT_NOT_FOUND;
- }
- error=read_block_chk(ffsbase,dev,&cur,EC(cur->data->fb_parent));
- if(error)
- return error;
- }else
- {
- if(cur->data->fb_sectype!=EC(ST_USERDIR)&&
- cur->data->fb_sectype!=EC(ST_ROOT))
- {
- *name=rest;
- *dir=cur;
- return ERROR_DIR_NOT_FOUND;
- }
- *dir=cur;
- block=hash(dev,rest);
- block=EC(cur->data->fb_hashtable[block]);
- for(;;)
- {
- if(!block)
- {
- *name=rest;
- *dir=cur;
- return ERROR_OBJECT_NOT_FOUND;
- }
- error=read_block_chk(ffsbase,dev,&cur,block);
- if(error)
- return error;
- touch_read(dev,cur);
- if(!namechk(dev,cur,rest))
- break;
- block=EC(cur->data->fb_nexthash);
- }
- }
- while(*rest)
- if(*rest++=='/')
- break;
- }
- *dir=cur;
- return 0;
- }
-
- static LONG lock(struct dev *dev, struct cinfo *block, ULONG mode)
- {
- ULONG protect;
- struct fh *fh;
- for(fh=(struct fh *)dev->vol->files.mlh_Head;
- fh->node.mln_Succ!=NULL;
- fh=(struct fh *)fh->node.mln_Succ)
- if(fh->block==block->num)
- if(mode&FMF_LOCK||fh->locked)
- return ERROR_OBJECT_IN_USE;
- touch_read(dev,block);
- protect=EC(block->data->fb_protect)^0xf;
- if((mode&FMF_EXECUTE)&&!(protect&FMF_EXECUTE))
- return ERROR_NOT_EXECUTABLE;
- if((mode&FMF_WRITE)&&!(protect&FMF_WRITE))
- return ERROR_WRITE_PROTECTED;
- if((mode&FMF_READ)&&!(protect&FMF_READ))
- return ERROR_READ_PROTECTED;
- return 0;
- }
-
- static LONG open(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, ULONG mode)
- {
- struct cinfo *dir;
- struct fh *new;
- LONG error;
- struct dev *dev;
- dev=(*fh)->block?(*fh)->vol->dev:(struct dev *)(*fh)->vol;
-
- new=(struct fh *)AllocMem(sizeof(struct fh),MEMF_CLEAR);
- if(new!=NULL)
- {
- error=findname(ffsbase,*fh,&name,&dir);
- if(!error)
- {
- error=lock(dev,dir,mode);
- if(!error)
- {
- new->vol=dev->vol;
- new->block=dir->num;
- if(mode&FMF_LOCK)
- new->locked=1;
- AddHead((struct List *)(dir->data->fb_sectype==EC(ST_FILE)?
- &dev->vol->files:&dev->vol->dirs),
- (struct Node *)&new->node);
- *fh=new;
- return 0;
- }
- }
- FreeMem(new,sizeof(struct fh));
- }else
- error=ERROR_NO_FREE_STORE;
- return error;
- }
-
- static LONG create_object
- (struct ffsbase *ffsbase, struct dev *dev, ULONG *blocknr,
- struct cinfo *block, STRPTR name, ULONG protect, ULONG type)
- {
- STRPTR s2;
- ULONG hashnr, pnum, next, a;
- LONG error;
-
- s2=name;
- while(*s2)
- if(*s2++=='/')
- return ERROR_DIR_NOT_FOUND;
- pnum=block->num;
- hashnr=hash(dev,name);
- next=block->data->fb_hashtable[hashnr];
- error=alloc_block(ffsbase,dev,blocknr);
- if(!error)
- {
- error=get_buffer(ffsbase,dev,&block);
- if(!error)
- {
- block->num=*blocknr;
- zerofill((STRPTR)block->data,dev->bsize);
- block->data->fb_type =EC(BT_STRUCT);
- block->data->fb_own =EC(*blocknr);
- block->data->fb_protect =EC(protect^0xf);
- /* TODO: set creation date */
- block->data->fb_nexthash=next;
- block->data->fb_parent =EC(pnum);
- block->data->fb_sectype =EC(type);
- setname(dev,block,name);
- block->data->fb_chksum =0;
- a=checksum(dev,block);
- block->data->fb_chksum =EC(a);
- touch_write(dev,block);
- error=read_block_chk(ffsbase,dev,&block,pnum);
- if(!error)
- {
- block->data->fb_hashtable[hashnr]=EC(*blocknr);
- block->data->fb_chksum=0;
- a=checksum(dev,block);
- block->data->fb_chksum=EC(a);
- touch_write(dev,block);
- return 0;
- }
- }
- (void)free_block(ffsbase,dev,*blocknr);
- }
- return error;
- }
-
- static LONG open_file(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, ULONG mode, ULONG protect)
- {
- struct cinfo *dir;
- struct fh *new;
- LONG error;
- struct dev *dev;
-
- dev=(*fh)->block?(*fh)->vol->dev:(struct dev *)(*fh)->vol;
-
- new=AllocMem(sizeof(struct fh),MEMF_CLEAR);
- if(new!=NULL)
- {
- error=findname(ffsbase,*fh,&name,&dir);
- if((mode&FMF_CREATE)&&error==ERROR_OBJECT_NOT_FOUND)
- error=create_object(ffsbase,dev,&new->block,dir,name,protect,ST_FILE);
- else if(!error)
- {
- touch_read(dev,dir);
- if(dir->data->fb_sectype!=EC((ULONG)ST_FILE))
- error=ERROR_OBJECT_WRONG_TYPE;
- else
- error=lock(dev,dir,mode);
- }
- if(!error)
- {
- new->vol =dev->vol;
- new->block=dir->num;
- if(mode&FMF_LOCK)
- new->locked=1;
- AddHead((struct List *)&dev->vol->files,(struct Node *)new);
- *fh=new;
- return 0;
- }
- FreeMem(new,sizeof(struct fh));
- }
- return error;
- }
-
- static LONG read(struct ffsbase *ffsbase, struct fh *fh, APTR buf, ULONG *numbytes)
- {
- struct cinfo *block;
- ULONG bpb,total,pos,rest,size,num=*numbytes;
- STRPTR buffer=(STRPTR)buf;
- struct dev *dev;
- LONG error;
-
- dev=fh->block?fh->vol->dev:(struct dev *)fh->vol;
- error=read_block_chk(ffsbase,dev,&block,fh->block);
- if(error)
- return error;
- bpb=fh->vol->id==ID_DOS_DISK?fh->vol->bsize-24:fh->vol->bsize;
- total=EC(block->data->fb_size);
- touch_read(dev,block);
- pos=fh->blocknr*bpb+fh->index;
- rest=total>pos?total-pos:0;
- num=num>rest?rest:num;
- size=bpb-fh->index;
- while(num)
- {
- if(size>num)
- size=num;
- if(!fh->current)
- {
- fh->current=fh->block;
- rest=fh->blocknr;
- while(rest--)
- {
- error=read_block_chk(ffsbase,dev,&block,fh->current);
- if(error)
- return error;
- fh->current=EC(block->data->fb_extend);
- touch_read(dev,block);
- }
- }
- error=read_block_chk(ffsbase,dev,&block,fh->current);
- if(error)
- return error;
- touch_read(dev,block);
- if(fh->vol->id==ID_DOS_DISK)
- {
- error=read_block_chk(ffsbase,dev,&block,EC(block->data->fb_data[HASHSIZE-1-fh->blocknr%(HASHSIZE)]));
- if(error)
- return error;
- CopyMem((STRPTR)(block->data->fb_data)+fh->index,buffer,size);
- }else
- {
- error=get_block(ffsbase,dev,&block,EC(block->data->fb_data[fh->blocknr%(HASHSIZE)]));
- if(error)
- return error;
- CopyMem((STRPTR)(block->data)+fh->index,buffer,size);
- }
- touch_read(dev,block);
- buffer+=size;
- num-=size;
- fh->index+=size;
- if(fh->index==bpb)
- {
- fh->index=0;
- fh->blocknr++;
- }
- if(!fh->blocknr%(HASHSIZE))
- {
- error=read_block_chk(ffsbase,dev,&block,fh->current);
- if(error)
- return error;
- fh->current=EC(block->data->fb_extend);
- touch_read(dev,block);
- }
- size=bpb;
- }
- *numbytes=buffer-(STRPTR)buf;
- return 0;
- }
-
- static LONG free_lock(struct ffsbase *ffsbase, struct fh *fh)
- {
- Remove((struct Node *)fh);
- FreeMem(fh,sizeof(struct fh));
- /* TODO: Dismount removed and unused disk */
- return 0;
- }
-
- static LONG create_dir(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, ULONG protect)
- {
- struct cinfo *block;
- struct dev *dev;
- struct fh *new;
- LONG error;
-
- dev=(*fh)->block?(*fh)->vol->dev:(struct dev *)(*fh)->vol;
-
- error=findname(ffsbase,*fh,&name,&block);
- if(!error)
- return ERROR_OBJECT_EXISTS;
- if(error!=ERROR_OBJECT_NOT_FOUND)
- return error;
- new=AllocMem(sizeof(struct fh),MEMF_CLEAR);
- if(new!=NULL)
- {
- error=create_object(ffsbase,dev,&new->block,block,name,protect,ST_USERDIR);
- if(!error)
- {
- new->vol=dev->vol;
- new->locked=1;
- AddHead((struct List *)&dev->vol->dirs,(struct Node *)new);
- *fh=new;
- return 0;
- }
- FreeMem(new,sizeof(struct fh));
- }
- return error;
- }
-
- static const ULONG sizes[]=
- { 0, offsetof(struct ExAllData,ed_Type), offsetof(struct ExAllData,ed_Size),
- offsetof(struct ExAllData,ed_Prot), offsetof(struct ExAllData,ed_Days),
- offsetof(struct ExAllData,ed_Comment), offsetof(struct ExAllData,ed_OwnerUID),
- sizeof(struct ExAllData)
- };
-
- static LONG examine_fib(struct ffsbase *ffsbase, struct dev *dev, ULONG block, struct ExAllData *ead, ULONG size, ULONG type)
- {
- struct cinfo *file;
- STRPTR next, end, name;
- ULONG l;
- LONG error;
- if(type>ED_OWNER)
- return ERROR_BAD_NUMBER;
- next=(STRPTR)ead+sizes[type];
- end=(STRPTR)ead+size;
- error=read_block_chk(ffsbase,dev,&file,block);
- if(error)
- return error;
- touch_read(dev,file);
- switch(type)
- {
- case ED_OWNER:
- ead->ed_OwnerUID=EC(file->data->fb_owner)>>16;
- ead->ed_OwnerGID=EC(file->data->fb_owner)&0xffff;
- case ED_COMMENT:
- name=(STRPTR)(file->data->fb_comment);
- l=*name++;
- if(l)
- {
- ead->ed_Comment=next;
- if(next+l+1>=end)
- return ERROR_BUFFER_OVERFLOW;
- do
- *next++=*name++;
- while(--l);
- *next++='\0';
- }else
- ead->ed_Comment=NULL;
- case ED_DATE:
- ead->ed_Days=EC(file->data->fb_days);
- ead->ed_Mins=EC(file->data->fb_mins);
- ead->ed_Ticks=EC(file->data->fb_ticks);
- case ED_PROTECTION:
- ead->ed_Prot=EC(file->data->fb_protect)^0xf;
- case ED_SIZE:
- ead->ed_Size=EC(file->data->fb_size);
- case ED_TYPE:
- ead->ed_Type=EC(file->data->fb_sectype);
- case ED_NAME:
- name=(STRPTR)(file->data->fb_name);
- l=*name++;
- ead->ed_Name=next;
- if(next+l+1>=end)
- return ERROR_BUFFER_OVERFLOW;
- if(l)
- do
- *next++=*name++;
- while(--l);
- *next++='\0';
- case 0:
- ead->ed_Next=(struct ExAllData *)(((ULONG)next+AROS_PTRALIGN-1)&~(AROS_PTRALIGN-1));
- }
- return 0;
- }
-
- static LONG examine(struct ffsbase *ffsbase, struct fh *fh, struct ExAllData *ead, ULONG size, ULONG type)
- {
- return examine_fib(ffsbase,fh->vol->dev,fh->block,ead,size,type);
- }
-
- static LONG examine_all(struct ffsbase *ffsbase, struct fh *dir, struct ExAllData *ead, ULONG size, ULONG type)
- {
- STRPTR end;
- struct ExAllData *last=NULL;
- struct cinfo *block;
- struct dev *dev;
- LONG error;
- dev=dir->block?dir->vol->dev:(struct dev *)dir->vol;
- end=(STRPTR)ead+size;
- error=read_block_chk(ffsbase,dev,&block,dir->block);
- if(error)
- return error;
- touch_read(dev,block);
- if(block->data->fb_sectype!=EC(ST_USERDIR)&&
- block->data->fb_sectype!=EC(ST_ROOT))
- return ERROR_OBJECT_WRONG_TYPE;
- if(!dir->blocknr)
- for(;dir->index<HASHSIZE;dir->index++)
- if(block->data->fb_hashtable[dir->index])
- {
- dir->blocknr=EC(block->data->fb_hashtable[dir->index]);
- break;
- }
- if(dir->index>=HASHSIZE)
- {
- dir->index=0;
- return ERROR_NO_MORE_ENTRIES;
- }
- do
- {
- error=examine_fib(ffsbase,dev,dir->blocknr,ead,end-(STRPTR)ead,type);
- if(error==ERROR_BUFFER_OVERFLOW)
- {
- if(last==NULL)
- return error;
- last->ed_Next=NULL;
- return 0;
- }
- last=ead;
- ead=ead->ed_Next;
- error=read_block_chk(ffsbase,dev,&block,dir->blocknr);
- if(error)
- return error;
- touch_read(dev,block);
- dir->blocknr=EC(block->data->fb_nexthash);
- if(!dir->blocknr)
- {
- error=read_block_chk(ffsbase,dev,&block,dir->block);
- if(error)
- return error;
- touch_read(dev,block);
- for(dir->index++;dir->index<HASHSIZE;dir->index++)
- if(block->data->fb_hashtable[dir->index])
- {
- dir->blocknr=EC(block->data->fb_hashtable[dir->index]);
- break;
- }
- }
- }while(dir->index<HASHSIZE);
- last->ed_Next=NULL;
- return 0;
- }
-
- void deventry(struct ffsbase *ffsbase)
- {
- struct IOFileSys *iofs;
- LONG error=0;
- struct vol *vol;
- /*
- Init device ports. AllocSignal() cannot fail because this is a
- freshly created task with all signal bits still free.
- */
- ffsbase->port.mp_SigBit=AllocSignal(-1);
- ffsbase->port.mp_Flags=PA_SIGNAL;
- ffsbase->dport.mp_SigBit=AllocSignal(-1);
- ffsbase->dport.mp_Flags=PA_SIGNAL;
-
- /* Get and process the messages. */
- for(;;)
- {
- while((iofs=(struct IOFileSys *)GetMsg(&ffsbase->port))!=NULL)
- {
- switch(iofs->IOFS.io_Command)
- {
- case (UWORD)-1:
- error=mount(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
- (STRPTR)iofs->io_Args[0], iofs->io_Args[1],
- (IPTR *)iofs->io_Args[2]);
- iofs->io_DosError=error;
- if(!error)
- (void)disk_change(ffsbase,(struct dev *)((struct fh *)iofs->IOFS.io_Unit)->vol);
- PutMsg(&ffsbase->rport,&iofs->IOFS.io_Message);
- continue;
- case FSA_OPEN:
- error=open(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
- (STRPTR)iofs->io_Args[0], iofs->io_Args[1]);
- break;
- case FSA_OPEN_FILE:
- error=open_file(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
- (STRPTR)iofs->io_Args[0], iofs->io_Args[1],
- iofs->io_Args[2]);
- break;
- case FSA_READ:
- error=read(ffsbase,(struct fh *)iofs->IOFS.io_Unit,
- (APTR)iofs->io_Args[0], &iofs->io_Args[1]);
- break;
- case FSA_CLOSE:
- error=free_lock(ffsbase,(struct fh *)iofs->IOFS.io_Unit);
- break;
- case FSA_CREATE_DIR:
- error=create_dir(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
- (STRPTR)iofs->io_Args[0], iofs->io_Args[1]);
- break;
- case FSA_EXAMINE:
- error=examine(ffsbase,(struct fh *)iofs->IOFS.io_Unit,
- (struct ExAllData *)iofs->io_Args[0],
- iofs->io_Args[1], iofs->io_Args[2]);
- break;
- case FSA_EXAMINE_ALL:
- error=examine_all(ffsbase,(struct fh *)iofs->IOFS.io_Unit,
- (struct ExAllData *)iofs->io_Args[0],
- iofs->io_Args[1], iofs->io_Args[2]);
- break;
- default:
- error=ERROR_NOT_IMPLEMENTED;
- break;
- }
- iofs->io_DosError=error;
- ReplyMsg(&iofs->IOFS.io_Message);
- }
- if(ffsbase->dlflag)
- {
- if(AttemptLockDosList(LDF_VOLUMES|LDF_WRITE)!=NULL)
- {
- while((vol=(struct vol *)RemHead((struct List *)&ffsbase->removed))!=NULL)
- {
- (void)RemDosEntry(vol->dlist);
- FreeDosEntry(vol->dlist);
- FreeMem(vol,sizeof(struct vol));
- }
- while((vol=(struct vol *)RemHead((struct List *)&ffsbase->inserted))!=NULL)
- {
- AddHead((struct List *)&ffsbase->mounted,(struct Node *)vol);
- (void)AddDosEntry(vol->dlist);
- }
- UnLockDosList(LDF_VOLUMES|LDF_WRITE);
- ffsbase->dlflag=0;
- }else
- {
- /* Wait some time then try again */
- Delay(TICKS_PER_SECOND/10);
- continue;
- }
- }
- WaitPort(&ffsbase->port);
- }
- }
-
- const char end=0;
-