home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / workbench / devs / ffs_handler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-27  |  42.0 KB  |  1,454 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: ffs_handler.c,v 1.4 1997/01/27 00:22:40 ldp Exp $
  4.     $Log: ffs_handler.c,v $
  5.     Revision 1.4  1997/01/27 00:22:40  ldp
  6.     Include proto instead of clib
  7.  
  8.     Revision 1.3  1996/12/10 13:59:49  aros
  9.     Moved #include into first column to allow makedepend to see it.
  10.  
  11.     Revision 1.2  1996/11/22 12:29:01  aros
  12.     More complete filesystem: Readonly and makedir.
  13.  
  14.     Desc:
  15.     Lang:
  16. */
  17. #include <devices/trackdisk.h>
  18. #include <exec/errors.h>
  19. #include <exec/types.h>
  20. #include <exec/resident.h>
  21. #include <exec/memory.h>
  22. #include <exec/semaphores.h>
  23. #include <proto/exec.h>
  24. #include <utility/tagitem.h>
  25. #include <proto/utility.h>
  26. #include <dos/dosextens.h>
  27. #include <dos/dosasl.h>
  28. #include <dos/exall.h>
  29. #include <dos/filesystem.h>
  30. #include <proto/dos.h>
  31. #include <aros/libcall.h>
  32. #include <aros/machine.h>
  33. #ifdef __GNUC__
  34. #include "ffs_handler_gcc.h"
  35. #endif
  36. #include <stddef.h>
  37.  
  38. /*
  39.  * The amiga (fast) filing system:
  40.  *
  41.  * Unlike some Un*x filesystems the amiga ffs is not split into a fixed inode
  42.  * and data section but instead the inode information is scattered across
  43.  * the entire disk. Each "inode" lives in it's own disk block (usually near
  44.  * the rest of the file) containing enough information to recover the entire
  45.  * file including name, parent directory, creation date and protection bits.
  46.  *
  47.  * The root directory block can be found in the middle of the partition.
  48.  * It contains a hashtable pointing to chained linear lists of file header
  49.  * or further (user) directory blocks. A file header block points to a
  50.  * number of simple data blocks and a list of further file list blocks
  51.  * containing pointers to data blocks.
  52.  *
  53.  * data blocks in the old amiga filing system consist of a small header
  54.  * and the data. data blocks in the fast filing system just consist of
  55.  * the stale data.
  56.  */
  57.  
  58. /* All information in the amiga FS is big endian */
  59.  
  60. #if BIG_ENDIAN
  61. #define EC(a) (a)
  62. #else
  63. #define EC(a) (((a)>>24)|(((a)&0xff0000)>>8)|(((a)&0xff00)<<8)|((a)<<24))
  64. #endif
  65.  
  66. /*
  67.  * Structure describing a single block of the amiga filesystem. The
  68.  * fb_hashtable field in the middle of the structure is sized so that
  69.  * the entire structure fills a complete block. Therefore all following fields
  70.  * don't live at a fixed offset and are just defines with HASHSIZE being
  71.  * the number of hashtable entries.
  72.  */
  73.  
  74. struct filesysblock
  75. {
  76.     ULONG fb_type;        /* block types (see below) */
  77.     ULONG fb_own;        /* own block number */
  78.     ULONG fb_blocks;        /* the number of blocks in the file */
  79.     ULONG fb_hashsize;        /* size of the hashtable */
  80.     ULONG fb_firstdata;        /* first data block */
  81.     ULONG fb_chksum;        /* sums the block to 0 */
  82.     ULONG fb_hashtable[122];    /* blocknumbers of blocksize/4-56 blocks */
  83. #define    fb_data        /* data for data blocks, data block numbers else */ fb_hashtable
  84. #define    fb_validated        /* ~0: disk is validated */    fb_hashtable[HASHSIZE]
  85. #define    fb_bam        /* 25 block allocation map blocks */ fb_hashtable+HASHSIZE+1
  86. #define    fb_bam_extend    /* first bam extend block */    fb_hashtable[HASHSIZE+26]
  87. #define    fb_days        /* modification date... */    fb_hashtable[HASHSIZE+27]
  88. #define    fb_mins        /* ...and time... */        fb_hashtable[HASHSIZE+28]
  89. #define    fb_ticks        /* ...dito */            fb_hashtable[HASHSIZE+29]
  90. #define    fb_name        /* file/disk/dir name */    fb_hashtable+HASHSIZE+30
  91. #define    fb_lastlink        /* chained links to file/dir */    fb_hashtable[HASHSIZE+38]
  92. #define    fb_nextlink                        fb_hashtable[HASHSIZE+39]
  93. #define    fb_vdays        /* volume altered time */    fb_hashtable[HASHSIZE+40]
  94. #define    fb_vmins                        fb_hashtable[HASHSIZE+41]
  95. #define    fb_vticks                        fb_hashtable[HASHSIZE+42]
  96. #define    fb_cdays        /* volume creation time */    fb_hashtable[HASHSIZE+43]
  97. #define    fb_cmins                        fb_hashtable[HASHSIZE+44]
  98. #define    fb_cticks                        fb_hashtable[HASHSIZE+45]
  99. #define    fb_nexthash        /* next hash chain entry */    fb_hashtable[HASHSIZE+46]
  100. #define    fb_parent        /* parent directory */        fb_hashtable[HASHSIZE+47]
  101. #define    fb_extend        /* next file list block */    fb_hashtable[HASHSIZE+48]
  102. #define    fb_sectype        /* secondary type */        fb_hashtable[HASHSIZE+49]
  103. #define    fb_owner        /* UID<<16+GID */        fb_hashtable[HASHSIZE+1]
  104. #define    fb_protect        /* protection bits^0xf */    fb_hashtable[HASHSIZE+2]
  105. #define    fb_size        /* size of the file in bytes */    fb_hashtable[HASHSIZE+3]
  106. #define    fb_comment        /* comment */            fb_hashtable+HASHSIZE+4
  107. #define    fb_id        /* filesystem magic number */    fb_type
  108. };
  109.  
  110. /* Block types */
  111. #define BT_STRUCT    2    /* describes the structure of the filesystem */
  112. #define BT_DATA        8    /* file data block */
  113. #define BT_FILELIST    16    /* file list block */
  114.  
  115. /* Secondary types (see dos/dosextens.h) */
  116. #if 0
  117. #define ST_ROOT        1    /* Root directory */
  118. #define ST_USERDIR    2    /* Normal directory */
  119. #define ST_FILE        -3    /* file header/list block */
  120. #endif
  121.  
  122. #define HASHSIZE dev->hashsize
  123.  
  124. #define NEWLIST(l)                          \
  125. ((l)->lh_Head=(struct Node *)&(l)->lh_Tail, \
  126.  (l)->lh_Tail=NULL,                         \
  127.  (l)->lh_TailPred=(struct Node *)(l))
  128.  
  129. extern const char name[];
  130. extern const char version[];
  131. extern const APTR inittabl[4];
  132. extern void *const functable[];
  133. extern const UBYTE datatable;
  134. extern struct ffsbase *AROS_SLIB_ENTRY(init,ffsdev)();
  135. extern void AROS_SLIB_ENTRY(open,ffsdev)();
  136. extern BPTR AROS_SLIB_ENTRY(close,ffsdev)();
  137. extern BPTR AROS_SLIB_ENTRY(expunge,ffsdev)();
  138. extern int AROS_SLIB_ENTRY(null,ffsdev)();
  139. extern void AROS_SLIB_ENTRY(beginio,ffsdev)();
  140. extern LONG AROS_SLIB_ENTRY(abortio,ffsdev)();
  141. extern void deventry();
  142. extern const char end;
  143.  
  144. /* Structure describing a cache block */
  145. struct cinfo
  146. {
  147.     ULONG lastacc;        /* time index for LRU cache */
  148.     ULONG num;            /* blocknumber of this block (-1: invalid) */
  149.     struct filesysblock *data;    /* Pointer to block */
  150.     LONG synced;        /* 0: needs to be written */
  151. };
  152.  
  153. /* Device node: one mounted drive */
  154. struct dev
  155. {
  156.     struct MinNode node;
  157.     ULONG numbuffers;        /* number of buffers */
  158.     UBYTE *cache;        /* cached blocks (contiguous to allow
  159.                  * reading of more than one buffer per
  160.                  * device access). */
  161.     struct cinfo *cinfos;    /* array of cinfo structures */
  162.     struct IOExtTD *iotd;    /* I/O request for this device */
  163.     ULONG accindex;        /* actual access index */
  164.     struct vol *vol;        /* Pointer to volume node */
  165.     LONG error;            /* ERROR_NO_DISK, ERROR_NOT_A_DOS_DISK or 0 */
  166.     
  167.     /* Describing the partition */
  168.     ULONG poffset;        /* number of the first partition block */
  169.     ULONG psize;        /* number of blocks of this partition */
  170.     ULONG reserved;        /* Reserved blocks */
  171.     ULONG bsize;        /* size of the blocks */
  172.     ULONG rnum;            /* number of the root block */
  173.     ULONG hashsize;        /* number of hashtable entries */
  174.     struct fh *fh;        /* Device handle */
  175.  
  176.     ULONG bmext;        /* current bitmap extend block */
  177.     ULONG fblock;        /* first free block */
  178. };
  179.  
  180. /* Volume node: one mounted disk */
  181. struct vol
  182. {
  183.     struct MinNode node;
  184.     struct dev *dev;        /* drive where the disk is inserted or NULL */
  185.     struct MinList files;    /* All filehandles for this disk */
  186.     struct MinList dirs;    /* All directory handles */
  187.  
  188.     /* Describing the partition */
  189.     ULONG psize;        /* See above */
  190.     ULONG reserved;
  191.     ULONG bsize;
  192.     ULONG rnum;
  193.     struct DosList *dlist;    /* pointer to dos list entry */
  194.  
  195.     ULONG cdays, cmins, cticks;
  196.     ULONG vdays, vmins, vticks;
  197.     
  198.     ULONG id;            /* filesystem type */
  199. };
  200.  
  201. /* A handle for a device, file or directory */
  202. struct fh
  203. {
  204.     struct MinNode node;
  205.     struct vol *vol;    /* Volume or device node */
  206.     ULONG block;    /* FIB or 0 for device handles */
  207.     LONG locked;    /* Object is locked */
  208.     /* actual Seek position */
  209.     ULONG current;    /* actual FIB for dirs, block for files */
  210.     ULONG blocknr;    /* the Nth block in the file */
  211.     ULONG index;    /* Hash chain# for dirs, the Nth byte in the block for files */
  212. };
  213.  
  214. int entry(void)
  215. {
  216.     /* If the device was executed by accident return error code. */
  217.     return -1;
  218. }
  219.  
  220. const struct Resident resident=
  221. {
  222.     RTC_MATCHWORD,
  223.     (struct Resident *)&resident,
  224.     (APTR)&end,
  225.     RTF_AUTOINIT,
  226.     1,
  227.     NT_LIBRARY,
  228.     0,
  229.     (char *)name,
  230.     (char *)&version[6],
  231.     (ULONG *)inittabl
  232. };
  233.  
  234. const char name[]="ffs.handler";
  235.  
  236. const char version[]="$VER: ffs handler 1.0 (28.3.96)\n\015";
  237.  
  238. const APTR inittabl[4]=
  239. {
  240.     (APTR)sizeof(struct ffsbase),
  241.     (APTR)functable,
  242.     (APTR)&datatable,
  243.     &AROS_SLIB_ENTRY(init,ffsdev)
  244. };
  245.  
  246. void *const functable[]=
  247. {
  248.     &AROS_SLIB_ENTRY(open,ffsdev),
  249.     &AROS_SLIB_ENTRY(close,ffsdev),
  250.     &AROS_SLIB_ENTRY(expunge,ffsdev),
  251.     &AROS_SLIB_ENTRY(null,ffsdev),
  252.     &AROS_SLIB_ENTRY(beginio,ffsdev),
  253.     &AROS_SLIB_ENTRY(abortio,ffsdev),
  254.     (void *)-1
  255. };
  256.  
  257. const UBYTE datatable=0;
  258.  
  259. #undef SysBase
  260. struct ExecBase *SysBase;
  261.  
  262. AROS_LH2(struct ffsbase *, init,
  263.  AROS_LHA(struct ffsbase *, ffsbase, D0),
  264.  AROS_LHA(BPTR,             segList,   A0),
  265.        struct ExecBase *, sysbase, 0, ffsdev)
  266. {
  267.     AROS_LIBFUNC_INIT
  268.     
  269.     /* This function is single-threaded by exec by calling Forbid. */
  270.  
  271.     struct Task *task;
  272.     APTR stack;
  273.  
  274.     /* Store arguments */
  275.     SysBase=sysbase;
  276.     ffsbase->seglist=segList;
  277.     NEWLIST((struct List *)&ffsbase->inserted);
  278.     NEWLIST((struct List *)&ffsbase->mounted);
  279.     NEWLIST((struct List *)&ffsbase->removed);
  280.     DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",39);
  281.     if(DOSBase!=NULL)
  282.     {
  283.     NEWLIST(&ffsbase->port.mp_MsgList);
  284.     ffsbase->port.mp_Node.ln_Type=NT_MSGPORT;
  285.     ffsbase->port.mp_Flags=PA_IGNORE;
  286.     NEWLIST(&ffsbase->dport.mp_MsgList);
  287.     ffsbase->dport.mp_Node.ln_Type=NT_MSGPORT;
  288.     ffsbase->dport.mp_Flags=PA_IGNORE;
  289.     NEWLIST(&ffsbase->rport.mp_MsgList);
  290.     ffsbase->rport.mp_Node.ln_Type=NT_MSGPORT;
  291.     ffsbase->rport.mp_Flags=PA_SIGNAL;
  292.     ffsbase->rport.mp_SigBit=SIGB_SINGLE;
  293.     InitSemaphore(&ffsbase->sigsem);
  294.  
  295.     task=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
  296.     if(task!=NULL)
  297.     {
  298.         ffsbase->port.mp_SigTask=task;
  299.         ffsbase->dport.mp_SigTask=task;
  300.         NEWLIST(&task->tc_MemEntry);
  301.         task->tc_Node.ln_Type=NT_TASK;
  302.         task->tc_Node.ln_Name="ffs.handler task";
  303.  
  304.         stack=AllocMem(2048,MEMF_PUBLIC);
  305.         if(stack!=NULL)
  306.         {
  307.         task->tc_SPLower=stack;
  308.         task->tc_SPUpper=(BYTE *)stack+2048;
  309. #if AROS_STACK_GROWS_DOWNWARDS
  310.         task->tc_SPReg=(BYTE *)task->tc_SPUpper-SP_OFFSET-sizeof(APTR);
  311.         ((APTR *)task->tc_SPUpper)[-1]=ffsbase;
  312. #else
  313.         task->tc_SPReg=(BYTE *)task->tc_SPLower-SP_OFFSET+sizeof(APTR);
  314.         *(APTR *)task->tc_SPLower=ffsbase;
  315. #endif
  316.  
  317.             if(AddTask(task,deventry,NULL)!=NULL)
  318.             return ffsbase;
  319.  
  320.         FreeMem(stack,2048);
  321.             }
  322.         FreeMem(task,sizeof(struct Task));
  323.     }
  324.     CloseLibrary((struct Library *)DOSBase);
  325.     }
  326.  
  327.     return NULL;
  328.     AROS_LIBFUNC_EXIT
  329. }
  330.  
  331. AROS_LH3(void, open,
  332.  AROS_LHA(struct IOFileSys *, iofs, A1),
  333.  AROS_LHA(ULONG,              unitnum, D0),
  334.  AROS_LHA(ULONG,              flags, D1),
  335.        struct ffsbase *, ffsbase, 1, ffsdev)
  336. {
  337.     AROS_LIBFUNC_INIT
  338.  
  339.     /* Keep compiler happy */
  340.     unitnum=flags=0;
  341.  
  342.     /* I have one more opener. */
  343.     ffsbase->device.dd_Library.lib_OpenCnt++;
  344.  
  345.     /* Send message to device task */
  346.     ObtainSemaphore(&ffsbase->sigsem);
  347.     ffsbase->rport.mp_SigTask=FindTask(NULL);
  348.     iofs->IOFS.io_Command=-1;
  349.     PutMsg(&ffsbase->port,&iofs->IOFS.io_Message);
  350.     WaitPort(&ffsbase->rport);
  351.     (void)GetMsg(&ffsbase->rport);
  352.     ReleaseSemaphore(&ffsbase->sigsem);
  353.  
  354.     if(!iofs->io_DosError)
  355.     {
  356.         iofs->IOFS.io_Error=0;
  357.         ffsbase->device.dd_Library.lib_Flags&=~LIBF_DELEXP;
  358.         return;
  359.     }
  360.  
  361.     /* set secondary error code and return */
  362.     iofs->IOFS.io_Error=IOERR_OPENFAIL;
  363.     ffsbase->device.dd_Library.lib_OpenCnt--;
  364.         
  365.     AROS_LIBFUNC_EXIT
  366. }
  367.  
  368. AROS_LH1(BPTR, close,
  369.  AROS_LHA(struct IOFileSys *, iofs, A1),
  370.        struct ffsbase *, ffsbase, 2, ffsdev)
  371. {
  372.     AROS_LIBFUNC_INIT
  373.     /*
  374.     This function is single-threaded by exec by calling Forbid.
  375.     If you break the Forbid() another task may enter this function
  376.     at the same time. Take care.
  377.     */
  378.  
  379.     /* Send message to device task */
  380.     ObtainSemaphore(&ffsbase->sigsem);
  381.     ffsbase->rport.mp_SigTask=FindTask(NULL);
  382.     iofs->IOFS.io_Command=-2;
  383.     PutMsg(&ffsbase->port,&iofs->IOFS.io_Message);
  384.     WaitPort(&ffsbase->rport);
  385.     ReleaseSemaphore(&ffsbase->sigsem);
  386.  
  387.     if(iofs->io_DosError)
  388.         return 0;
  389.  
  390.     /* Let any following attemps to use the device crash hard. */
  391.     iofs->IOFS.io_Device=(struct Device *)-1;
  392.  
  393.     /* I have one fewer opener. */
  394.     if(!--ffsbase->device.dd_Library.lib_OpenCnt)
  395.     {
  396.     /* Delayed expunge pending? */
  397.     if(ffsbase->device.dd_Library.lib_Flags&LIBF_DELEXP)
  398.         /* Then expunge the device */
  399.         return expunge();
  400.     }
  401.     return 0;
  402.     AROS_LIBFUNC_EXIT
  403. }
  404.  
  405. AROS_LH0(BPTR, expunge, struct ffsbase *, ffsbase, 3, ffsdev)
  406. {
  407.     AROS_LIBFUNC_INIT
  408.  
  409.     BPTR ret;
  410.     /*
  411.     This function is single-threaded by exec by calling Forbid.
  412.     Never break the Forbid() or strange things might happen.
  413.     */
  414.  
  415.     /* Test for openers. */
  416.     if(ffsbase->device.dd_Library.lib_OpenCnt)
  417.     {
  418.     /* Set the delayed expunge flag and return. */
  419.     ffsbase->device.dd_Library.lib_Flags|=LIBF_DELEXP;
  420.     return 0;
  421.     }
  422.  
  423.     /* Kill device task and free all resources */
  424.     RemTask(ffsbase->port.mp_SigTask);
  425.     FreeMem(((struct Task *)ffsbase->port.mp_SigTask)->tc_SPLower,2048);
  426.     FreeMem(ffsbase->port.mp_SigTask,sizeof(struct Task));
  427.     CloseLibrary((struct Library *)ffsbase->dosbase);
  428.  
  429.     /* Get rid of the device. Remove it from the list. */
  430.     Remove(&ffsbase->device.dd_Library.lib_Node);
  431.  
  432.     /* Get returncode here - FreeMem() will destroy the field. */
  433.     ret=ffsbase->seglist;
  434.  
  435.     /* Free the memory. */
  436.     FreeMem((char *)ffsbase-ffsbase->device.dd_Library.lib_NegSize,
  437.         ffsbase->device.dd_Library.lib_NegSize+ffsbase->device.dd_Library.lib_PosSize);
  438.  
  439.     return ret;
  440.     AROS_LIBFUNC_EXIT
  441. }
  442.  
  443. AROS_LH0I(int, null, struct ffsbase *, ffsbase, 4, ffsdev)
  444. {
  445.     AROS_LIBFUNC_INIT
  446.     return 0;
  447.     AROS_LIBFUNC_EXIT
  448. }
  449.  
  450. AROS_LH1(void, beginio,
  451.  AROS_LHA(struct IOFileSys *, iofs, A1),
  452.        struct ffsbase *, ffsbase, 5, ffsdev)
  453. {
  454.     AROS_LIBFUNC_INIT
  455.  
  456.     /* Nothing is done quick */
  457.     iofs->IOFS.io_Flags&=~IOF_QUICK;
  458.     
  459.     /* So let the device task do it */
  460.     PutMsg(&ffsbase->port,&iofs->IOFS.io_Message);
  461.     
  462.     AROS_LIBFUNC_EXIT
  463. }
  464.  
  465. AROS_LH1(LONG, abortio,
  466.  AROS_LHA(struct IOFileSys *, iofs, A1),
  467.        struct ffsbase *, ffsbase, 6, ffsdev)
  468. {
  469.     AROS_LIBFUNC_INIT
  470.     return 0;
  471.     AROS_LIBFUNC_EXIT
  472. }
  473.  
  474. #define touch_read(dev,cinfo) ((cinfo)->lastacc=((dev)->accindex)++)
  475. #define touch_write(dev,cinfo) ((cinfo)->lastacc=((dev)->accindex)++,(cinfo)->synced=0)
  476.  
  477. static LONG write_block(struct ffsbase *ffsbase, struct dev *dev, struct cinfo *cinfo)
  478. {
  479.     cinfo->synced=1;
  480.     dev->iotd->iotd_Req.io_Command=CMD_WRITE;
  481.     dev->iotd->iotd_Req.io_Data   =cinfo->data;
  482.     dev->iotd->iotd_Req.io_Offset =(dev->poffset+cinfo->num)*dev->bsize;
  483.     dev->iotd->iotd_Req.io_Length =dev->bsize;
  484.     return DoIO((struct IORequest *)dev->iotd);
  485. }
  486.  
  487. static LONG get_buffer(struct ffsbase *ffsbase, struct dev *dev, struct cinfo **cinfo)
  488. {
  489.     LONG ret=0;
  490.     struct cinfo *buf;
  491.     ULONG max,i;
  492.     buf=dev->cinfos;
  493.     max=dev->accindex-buf->lastacc;
  494.     for(i=1;i<dev->numbuffers;i++)
  495.         if(dev->accindex-dev->cinfos[i].lastacc>max)
  496.         {
  497.             buf=&dev->cinfos[i];
  498.             max=dev->accindex-buf->lastacc;
  499.         }
  500.     if(!buf->synced)
  501.         ret=write_block(ffsbase,dev,buf);
  502.     *cinfo=buf;
  503.     return ret;
  504. }
  505.  
  506. LONG get_block(struct ffsbase *ffsbase, struct dev *dev, struct cinfo **cinfo, ULONG num)
  507. {
  508.     ULONG i;
  509.     int ret;
  510.     if(dev==NULL)
  511.         return ERROR_DEVICE_NOT_MOUNTED;
  512.     for(i=0;i<dev->numbuffers;i++)
  513.     if(dev->cinfos[i].num==num)
  514.     {
  515.         *cinfo=&dev->cinfos[i];
  516.         return 0;
  517.     }
  518.     ret=get_buffer(ffsbase,dev,cinfo);
  519.     if(ret)
  520.         return ret;
  521.     (*cinfo)->num=~0;
  522.     (*cinfo)->synced=0;
  523.     dev->iotd->iotd_Req.io_Command=CMD_READ;
  524.     dev->iotd->iotd_Req.io_Data   =(*cinfo)->data;
  525.     dev->iotd->iotd_Req.io_Offset =(dev->poffset+num)*dev->bsize;
  526.     dev->iotd->iotd_Req.io_Length =dev->bsize;
  527.     ret=DoIO((struct IORequest *)dev->iotd);
  528.     if(ret)
  529.         return 1; /* I/O Error */
  530.     (*cinfo)->num=num;
  531.     (*cinfo)->synced=1;
  532.     return 0;
  533. }
  534.  
  535. ULONG checksum(struct dev *dev, struct cinfo *cinfo)
  536. {
  537.     ULONG i;
  538. #if AROS_BIG_ENDIAN
  539.     ULONG *p=(ULONG *)cinfo->data, sum=0;
  540.     for(i=0;i<dev->bsize/4;i++)
  541.     sum+=*p++;
  542.     return -sum;
  543. #else
  544.     UBYTE *p=(UBYTE *)cinfo->data;
  545.     ULONG s1=0, s2=0, s3=0, s4=0;
  546.     for(i=0;i<dev->bsize/4;i++)
  547.         s1+=*p++, s2+=*p++, s3+=*p++, s4+=*p++;
  548.     return -(((s1*256+s2)*256+s3)*256+s4);
  549. #endif
  550. }
  551.  
  552. LONG read_block_chk(struct ffsbase *ffsbase, struct dev *dev, struct cinfo **cinfo, ULONG num)
  553. {
  554.     int ret;
  555.     ret=get_block(ffsbase,dev,cinfo,num);
  556.     if(ret)
  557.         return ret;
  558.     if(checksum(dev,*cinfo))
  559.     {KPrintF("%s\n",(*cinfo)->data->fb_name);
  560.     return ERROR_BAD_NUMBER; /* Checksum error */}
  561.     return 0;
  562. }
  563.  
  564. void dump(struct ffsbase *ffsbase, struct cinfo *block)
  565. {
  566.     int i;
  567.     for(i=0;i<128;i++)
  568.         KPrintF("%lx ",EC(((ULONG *)block->data)[i]));
  569.     KPrintF("\n");
  570. }
  571.  
  572. static LONG alloc_block(struct ffsbase *ffsbase, struct dev *dev, ULONG *newblk)
  573. {
  574.     struct cinfo *block;
  575.     ULONG a, b;
  576.     ULONG i, imax, k, kmax, kmax2;
  577.     ULONG bpb, bblock, btotal, next;
  578.     LONG error;
  579.     
  580.     bpb=8*(dev->bsize-4);
  581.     bblock=dev->fblock/bpb;
  582.     btotal=(dev->psize-dev->reserved+bpb-1)/bpb;
  583.     k=1+(dev->fblock%bpb)/32;
  584.     for(;;)
  585.     {
  586.     if(bblock<25)
  587.     {
  588.         i=7+HASHSIZE+bblock;
  589.         imax=7+25+HASHSIZE;
  590.     }else
  591.     {
  592.         i=(bblock-25)%(dev->bsize/4-1);
  593.         imax=dev->bsize/4-1;
  594.     }
  595.     for(;i<imax;i++)
  596.     {
  597.         if(bblock>=btotal)
  598.             return ERROR_DISK_FULL;
  599.         if(bblock<25)
  600.             error=read_block_chk(ffsbase,dev,&block,dev->bmext);
  601.         else
  602.             error=get_block(ffsbase,dev,&block,dev->bmext);
  603.         if(error)
  604.             return error;
  605.         next=EC(((ULONG *)block->data)[imax]);
  606.         touch_read(dev,block);
  607.         error=read_block_chk(ffsbase,dev,&block,EC(((ULONG *)block->data)[i]));
  608.         if(error)
  609.             return error;
  610.         kmax=dev->bsize/4;
  611.         kmax2=1+(dev->psize-dev->reserved-bblock*bpb+31)/32;
  612.         if(kmax>kmax2)
  613.             kmax=kmax2;
  614.         touch_read(dev,block);
  615.         for(;k<kmax;k++)
  616.             if(((ULONG *)block->data)[k])
  617.             {
  618.                 a=EC(((ULONG *)block->data)[k]);
  619.                 b=a&-a;
  620.                 a&=~b;
  621.                 b=(b&0xffff0000?16:0)+(b&0xff00ff00?8:0)+(b&0xf0f0f0f0?4:0)+
  622.                   (b&0xcccccccc?2:0) +(b&0xaaaaaaaa?1:0);
  623.                 dev->fblock=bblock*bpb+(k-1)*32+b;
  624.                 if(dev->fblock+dev->reserved>=dev->psize)
  625.                     return ERROR_DISK_FULL;
  626.                 *newblk=dev->fblock+dev->reserved;
  627.                 ((ULONG *)block->data)[k]=EC(a);
  628.                 *(ULONG *)block->data=0;
  629.                 a=checksum(dev,block);
  630.                 *(ULONG *)block->data=EC(a);
  631.                 touch_write(dev,block);
  632.                 return 0;
  633.             }
  634.         bblock++;
  635.         dev->fblock=bblock*bpb;
  636.         k=1;
  637.     }
  638.     dev->bmext=next;
  639.     }
  640. }
  641.  
  642. static LONG free_block(struct ffsbase *ffsbase, struct dev *dev, ULONG blk)
  643. {
  644.     struct cinfo *block;
  645.     ULONG a, k, old, oldbblock, bpb, bblock, btotal, next;
  646.     LONG error;
  647.  
  648.     bpb=8*(dev->bsize-4);
  649.     oldbblock=dev->fblock/bpb;
  650.     btotal=(dev->psize-dev->reserved+bpb-1)/bpb;
  651.     bblock=blk/bpb;
  652.     k=blk%bpb;
  653.     if(bblock<oldbblock)
  654.     {
  655.         dev->bmext=dev->rnum;
  656.         if(bblock>25)
  657.         {
  658.         error=read_block_chk(ffsbase,dev,&block,dev->bmext);
  659.             if(error)
  660.                 return error;
  661.             dev->bmext=EC(((ULONG *)block->data)[7+25+HASHSIZE]);
  662.             touch_read(dev,block);
  663.             old=(old-25)/(dev->bsize/4-1);
  664.             while(old--)
  665.             {
  666.             error=get_block(ffsbase,dev,&block,dev->bmext);
  667.                 if(error)
  668.                     return error;
  669.             dev->bmext=EC(((ULONG *)block->data)[dev->bsize/4-1]);
  670.             touch_read(dev,block);
  671.             }
  672.         }
  673.     }
  674.     if(dev->fblock>blk)
  675.         dev->fblock=blk;
  676.     if(bblock<25)
  677.     {
  678.     error=read_block_chk(ffsbase,dev,&block,dev->bmext);
  679.     next=EC(((ULONG *)block->data)[7+HASHSIZE+bblock]);
  680.     }else
  681.     {
  682.         error=get_block(ffsbase,dev,&block,dev->bmext);
  683.     next=EC(((ULONG *)block->data)[(bblock-25)%(dev->bsize/4-1)]);
  684.     }
  685.     if(error)
  686.         return error;
  687.     touch_read(dev,block);
  688.     error=read_block_chk(ffsbase,dev,&block,next);
  689.     if(error)
  690.         return error;
  691.     a=EC(((ULONG *)block->data)[k/32+1]);
  692.     a|=1<<(k&31);
  693.     ((ULONG *)block->data)[k/32+1]=EC(a);
  694.     touch_write(dev,block);
  695.     return 0;
  696. }
  697.  
  698. static void zerofill(UBYTE *address, ULONG size)
  699. {
  700.     while(size--)
  701.     *address++=0;
  702. }
  703.  
  704. LONG mount(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, LONG unit, IPTR *envec)
  705. {
  706.     struct dev *dev;
  707.     ULONG i,tracksize;
  708.     dev=(struct dev *)AllocMem(sizeof(struct dev),MEMF_CLEAR);
  709.     if(dev!=NULL)
  710.     {
  711.         dev->fh=(struct fh *)AllocMem(sizeof(struct fh),MEMF_CLEAR);
  712.         if(dev->fh!=NULL)
  713.         {
  714.             dev->fh->vol=(struct vol *)dev;
  715.             dev->cache=(UBYTE *)AllocMem(envec[DE_NUMBUFFERS]*envec[DE_BLOCKSIZE],MEMF_CLEAR);
  716.             if(dev->cache!=NULL)
  717.             {
  718.                 dev->cinfos=(struct cinfo *)AllocMem(sizeof(struct cinfo)*envec[DE_NUMBUFFERS],MEMF_CLEAR);
  719.                 if(dev->cinfos!=NULL)
  720.                 {
  721.                     for(i=0;i<envec[DE_NUMBUFFERS];i++)
  722.                     {
  723.                         dev->cinfos[i].data=(struct filesysblock *)&dev->cache[envec[DE_BLOCKSIZE]*i];
  724.                         dev->cinfos[i].num=-1;
  725.                         dev->cinfos[i].synced=1;
  726.                     }
  727.                     tracksize=envec[DE_NUMHEADS]*envec[DE_BLKSPERTRACK];
  728.                     dev->numbuffers=envec[DE_NUMBUFFERS];
  729.                     dev->poffset=tracksize*envec[DE_LOWCYL];
  730.                     dev->psize=tracksize*(envec[DE_HIGHCYL]-envec[DE_LOWCYL]+1);
  731.                     dev->reserved=envec[DE_RESERVEDBLKS];
  732.                     dev->bsize=envec[DE_BLOCKSIZE];
  733.                     dev->rnum=(dev->psize-dev->reserved-1)/2+dev->reserved;
  734.                     dev->hashsize=(dev->bsize-224)/4;
  735.                     dev->iotd=(struct IOExtTD *)CreateIORequest(&ffsbase->dport,sizeof(struct IOExtTD));
  736.                     if(dev->iotd!=NULL)
  737.             {
  738.                         if(!OpenDevice(name,unit,(struct IORequest *)dev->iotd,0))
  739.                         {
  740.                             *fh=dev->fh;
  741.                             return 0;
  742.                         }
  743.                         DeleteIORequest((struct IORequest *)dev->iotd);
  744.                     }
  745.                     FreeMem(dev->cinfos,sizeof(struct cinfo)*envec[DE_NUMBUFFERS]);
  746.                 }
  747.                 FreeMem(dev->cache,envec[DE_NUMBUFFERS]*envec[DE_BLOCKSIZE]);
  748.             }
  749.             FreeMem(dev->fh,sizeof(struct fh));
  750.         }
  751.         FreeMem(dev,sizeof(struct dev));
  752.     }
  753.     return ERROR_NO_FREE_STORE;
  754. }
  755.  
  756. void flush(struct dev *dev)
  757. {
  758.     ULONG i;
  759.     for(i=0;i<dev->numbuffers;i++)
  760.     {
  761.         dev->cinfos[i].num=-1;
  762.         dev->cinfos[i].synced=1;
  763.     }
  764. }
  765.  
  766. LONG disk_change(struct ffsbase *ffsbase, struct dev *dev)
  767. {
  768.     struct cinfo *root, *boot;
  769.     ULONG id;
  770.     LONG error;
  771.     struct vol *vol;
  772.     struct fh *fh;
  773.     flush(dev);
  774.     error=get_block(ffsbase,dev,&boot,0);
  775.     if(error)
  776.         return dev->error=error;
  777.     id=EC(boot->data->fb_id);
  778.     if(id!=ID_DOS_DISK&&id!=ID_FFS_DISK)
  779.         return dev->error=ERROR_NOT_A_DOS_DISK;
  780.     error=read_block_chk(ffsbase,dev,&root,dev->rnum);
  781.     if(error==ERROR_BAD_NUMBER||EC(root->data->fb_hashsize)!=dev->hashsize||
  782.         root->data->fb_type!=EC(BT_STRUCT)||root->data->fb_sectype!=EC(ST_ROOT)||
  783.         root->data->fb_validated!=EC(~0ul))
  784.         return dev->error=ERROR_NOT_A_DOS_DISK;
  785. #if 0
  786.     for(dev=ffsbase->volumes.mlh_Head;
  787.     dev->node.mln_Succ!=NULL;
  788.     dev=dev->node.mln_Succ)
  789.     if(dev->cdays ==root->data->fb_cdays &&
  790.        dev->cmins ==root->data->fb_cmins &&
  791.        dev->cticks==root->data->fb_cticks&&
  792.        dev->vdays ==root->data->fb_vdays &&
  793.        dev->vmins ==root->data->fb_vmins &&
  794.        dev->vticks==root->data->fb_vticks&&
  795.     {
  796.     }
  797. #endif
  798.     vol=AllocMem(sizeof(struct vol),MEMF_PUBLIC);
  799.     if(vol!=NULL)
  800.     {
  801.         fh=AllocMem(sizeof(struct fh),MEMF_CLEAR);
  802.         if(fh!=NULL)
  803.         {
  804.             UBYTE buf[32];
  805.             ULONG l;
  806.             fh->vol  =vol;
  807.             fh->block=dev->rnum;
  808.             vol->id      =id;
  809.             vol->bsize   =dev->bsize;
  810.             vol->psize   =dev->psize;
  811.             vol->reserved=dev->reserved;
  812.             vol->cdays =EC(root->data->fb_cdays);
  813.             vol->cmins =EC(root->data->fb_cmins);
  814.             vol->cticks=EC(root->data->fb_cticks);
  815.             vol->vdays =EC(root->data->fb_vdays);
  816.             vol->vmins =EC(root->data->fb_vmins);
  817.             vol->vticks=EC(root->data->fb_vticks);
  818.             NEWLIST((struct List *)&vol->files);
  819.             NEWLIST((struct List *)&vol->dirs);
  820.             l=*(UBYTE *)(root->data->fb_name);
  821.             if(l<31)
  822.             {
  823.                 buf[l]=0;
  824.                 CopyMem((STRPTR)(root->data->fb_name)+1,buf,l);
  825.                 vol->dlist=MakeDosEntry(buf,DLT_VOLUME);
  826.                 if(vol->dlist!=NULL)
  827.                 {
  828.                     vol->dlist->dol_Device=&ffsbase->device;
  829.                     vol->dlist->dol_Unit=(struct Unit *)fh;
  830.                     dev->vol=vol;
  831.                     vol->dev=dev;
  832.                     dev->bmext=dev->rnum;
  833.                     dev->fblock=0;
  834.                     AddTail((struct List *)&ffsbase->inserted,(struct Node *)vol);
  835.                     ffsbase->dlflag=1;
  836.                     return 0;
  837.                 }
  838.             }
  839.             FreeMem(fh,sizeof(struct fh));
  840.         }
  841.         FreeMem(dev,sizeof(struct dev));
  842.     }
  843.     return ERROR_NO_FREE_STORE;
  844. }
  845.  
  846. #define toupper_ffs(c) ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c))
  847.  
  848. static int namechk(struct dev *dev, struct cinfo *cur, STRPTR name)
  849. {
  850.     STRPTR s1=(STRPTR)(cur->data->fb_name);
  851.     ULONG l=*s1++;
  852.     if(l)
  853.     do
  854.     {
  855.             if(toupper_ffs(*s1)!=toupper_ffs(*name)||*name=='/')
  856.                 return 1;
  857.             s1++, name++;
  858.         }
  859.         while(--l);
  860.     return *name;
  861. }
  862.  
  863. static void setname(struct dev *dev, struct cinfo *block, STRPTR name)
  864. {
  865.     STRPTR s1=(STRPTR)(block->data->fb_name)+1;
  866.     ULONG l;
  867.     for(l=0;l<30;l++)
  868.     {
  869.     if(!*name)
  870.         break;
  871.     *s1++=*name++;
  872.     }
  873.     *(STRPTR)(block->data->fb_name)=l;
  874.     for(;l<31;l++)
  875.         *s1++=0;
  876. }
  877.  
  878. static ULONG hash(struct dev *dev, STRPTR name)
  879. {
  880.     ULONG l, h=0;
  881.     STRPTR s2=name;
  882.     while(*s2&&*s2!='/')
  883.         s2++;
  884.     l=s2-name>30?30:s2-name;
  885.     h=l;
  886.     while(l--)
  887.     {
  888.         h=(h*13+toupper_ffs(*name))&0x7ff;
  889.         name++;
  890.     }
  891.     return h%HASHSIZE;
  892. }
  893.  
  894. static LONG findname(struct ffsbase *ffsbase, struct fh *fh, STRPTR *name, struct cinfo **dir)
  895. {
  896.     LONG error;
  897.     struct cinfo *cur=*dir;
  898.     char *rest=*name;
  899.     ULONG block;
  900.     struct dev *dev;
  901.  
  902.     block=fh->block;
  903.     if(!block)
  904.     {
  905.         dev=(struct dev *)fh->vol;
  906.         block=dev->rnum;
  907.     }else
  908.         dev=fh->vol->dev;
  909.     error=read_block_chk(ffsbase,dev,&cur,block);
  910.     if(error)
  911.     return error;
  912.  
  913.     while(*rest)
  914.     {
  915.     touch_read(dev,cur);
  916.     if(*rest=='/')
  917.     {
  918.         if(cur->data->fb_sectype==EC(ST_ROOT))
  919.         {
  920.             *name=rest;
  921.             *dir=cur;
  922.         return ERROR_OBJECT_NOT_FOUND;
  923.         }
  924.         error=read_block_chk(ffsbase,dev,&cur,EC(cur->data->fb_parent));
  925.         if(error)
  926.             return error;
  927.     }else
  928.     {
  929.         if(cur->data->fb_sectype!=EC(ST_USERDIR)&&
  930.            cur->data->fb_sectype!=EC(ST_ROOT))
  931.         {
  932.             *name=rest;
  933.             *dir=cur;
  934.         return ERROR_DIR_NOT_FOUND;
  935.         }
  936.         *dir=cur;
  937.         block=hash(dev,rest);
  938.         block=EC(cur->data->fb_hashtable[block]);
  939.         for(;;)
  940.         {
  941.                 if(!block)
  942.         {
  943.             *name=rest;
  944.             *dir=cur;
  945.             return ERROR_OBJECT_NOT_FOUND;
  946.         }
  947.                 error=read_block_chk(ffsbase,dev,&cur,block);
  948.                 if(error)
  949.                     return error;
  950.         touch_read(dev,cur);
  951.         if(!namechk(dev,cur,rest))
  952.             break;
  953.         block=EC(cur->data->fb_nexthash);
  954.         }
  955.     }
  956.     while(*rest)
  957.         if(*rest++=='/')
  958.             break;
  959.     }
  960.     *dir=cur;
  961.     return 0;
  962. }
  963.  
  964. static LONG lock(struct dev *dev, struct cinfo *block, ULONG mode)
  965. {
  966.     ULONG protect;
  967.     struct fh *fh;
  968.     for(fh=(struct fh *)dev->vol->files.mlh_Head;
  969.     fh->node.mln_Succ!=NULL;
  970.     fh=(struct fh *)fh->node.mln_Succ)
  971.     if(fh->block==block->num)
  972.         if(mode&FMF_LOCK||fh->locked)
  973.             return ERROR_OBJECT_IN_USE;
  974.     touch_read(dev,block);
  975.     protect=EC(block->data->fb_protect)^0xf;
  976.     if((mode&FMF_EXECUTE)&&!(protect&FMF_EXECUTE))
  977.         return ERROR_NOT_EXECUTABLE;
  978.     if((mode&FMF_WRITE)&&!(protect&FMF_WRITE))
  979.     return ERROR_WRITE_PROTECTED;
  980.     if((mode&FMF_READ)&&!(protect&FMF_READ))
  981.     return ERROR_READ_PROTECTED;
  982.     return 0;
  983. }
  984.  
  985. static LONG open(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, ULONG mode)
  986. {
  987.     struct cinfo *dir;
  988.     struct fh *new;
  989.     LONG error;
  990.     struct dev *dev;
  991.     dev=(*fh)->block?(*fh)->vol->dev:(struct dev *)(*fh)->vol;
  992.  
  993.     new=(struct fh *)AllocMem(sizeof(struct fh),MEMF_CLEAR);
  994.     if(new!=NULL)
  995.     {
  996.         error=findname(ffsbase,*fh,&name,&dir);
  997.         if(!error)
  998.         {
  999.             error=lock(dev,dir,mode);
  1000.             if(!error)
  1001.             {
  1002.                 new->vol=dev->vol;
  1003.         new->block=dir->num;
  1004.         if(mode&FMF_LOCK)
  1005.             new->locked=1;
  1006.             AddHead((struct List *)(dir->data->fb_sectype==EC(ST_FILE)?
  1007.                 &dev->vol->files:&dev->vol->dirs),
  1008.                 (struct Node *)&new->node);
  1009.                 *fh=new;
  1010.                 return 0;
  1011.             }
  1012.         }
  1013.         FreeMem(new,sizeof(struct fh));
  1014.     }else
  1015.         error=ERROR_NO_FREE_STORE;
  1016.     return error;
  1017. }
  1018.  
  1019. static LONG create_object
  1020. (struct ffsbase *ffsbase, struct dev *dev, ULONG *blocknr,
  1021.  struct cinfo *block, STRPTR name, ULONG protect, ULONG type)
  1022. {
  1023.     STRPTR s2;
  1024.     ULONG hashnr, pnum, next, a;
  1025.     LONG error;
  1026.  
  1027.     s2=name;
  1028.     while(*s2)
  1029.         if(*s2++=='/')
  1030.             return ERROR_DIR_NOT_FOUND;
  1031.     pnum=block->num;
  1032.     hashnr=hash(dev,name);
  1033.     next=block->data->fb_hashtable[hashnr];
  1034.     error=alloc_block(ffsbase,dev,blocknr);
  1035.     if(!error)
  1036.     {
  1037.         error=get_buffer(ffsbase,dev,&block);
  1038.         if(!error)
  1039.         {
  1040.             block->num=*blocknr;
  1041.             zerofill((STRPTR)block->data,dev->bsize);
  1042.             block->data->fb_type    =EC(BT_STRUCT);
  1043.             block->data->fb_own     =EC(*blocknr);
  1044.             block->data->fb_protect =EC(protect^0xf);
  1045.             /* TODO: set creation date */
  1046.             block->data->fb_nexthash=next;
  1047.             block->data->fb_parent  =EC(pnum);
  1048.             block->data->fb_sectype =EC(type);
  1049.             setname(dev,block,name);
  1050.             block->data->fb_chksum  =0;
  1051.             a=checksum(dev,block);
  1052.             block->data->fb_chksum  =EC(a);
  1053.             touch_write(dev,block);
  1054.             error=read_block_chk(ffsbase,dev,&block,pnum);
  1055.             if(!error)
  1056.             {
  1057.                 block->data->fb_hashtable[hashnr]=EC(*blocknr);
  1058.                 block->data->fb_chksum=0;
  1059.                 a=checksum(dev,block);
  1060.                 block->data->fb_chksum=EC(a);
  1061.                 touch_write(dev,block);
  1062.                 return 0;
  1063.             }
  1064.         }
  1065.         (void)free_block(ffsbase,dev,*blocknr);
  1066.     }
  1067.     return error;
  1068. }
  1069.  
  1070. static LONG open_file(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, ULONG mode, ULONG protect)
  1071. {
  1072.     struct cinfo *dir;
  1073.     struct fh *new;
  1074.     LONG error;
  1075.     struct dev *dev;
  1076.  
  1077.     dev=(*fh)->block?(*fh)->vol->dev:(struct dev *)(*fh)->vol;
  1078.  
  1079.     new=AllocMem(sizeof(struct fh),MEMF_CLEAR);
  1080.     if(new!=NULL)
  1081.     {
  1082.         error=findname(ffsbase,*fh,&name,&dir);
  1083.         if((mode&FMF_CREATE)&&error==ERROR_OBJECT_NOT_FOUND)
  1084.             error=create_object(ffsbase,dev,&new->block,dir,name,protect,ST_FILE);
  1085.         else if(!error)
  1086.         {
  1087.             touch_read(dev,dir);
  1088.             if(dir->data->fb_sectype!=EC((ULONG)ST_FILE))
  1089.                 error=ERROR_OBJECT_WRONG_TYPE;
  1090.             else
  1091.                 error=lock(dev,dir,mode);
  1092.         }
  1093.         if(!error)
  1094.         {
  1095.             new->vol  =dev->vol;
  1096.         new->block=dir->num;
  1097.         if(mode&FMF_LOCK)
  1098.         new->locked=1;
  1099.           AddHead((struct List *)&dev->vol->files,(struct Node *)new);
  1100.             *fh=new;
  1101.             return 0;
  1102.         }
  1103.         FreeMem(new,sizeof(struct fh));
  1104.     }
  1105.     return error;
  1106. }
  1107.  
  1108. static LONG read(struct ffsbase *ffsbase, struct fh *fh, APTR buf, ULONG *numbytes)
  1109. {
  1110.     struct cinfo *block;
  1111.     ULONG bpb,total,pos,rest,size,num=*numbytes;
  1112.     STRPTR buffer=(STRPTR)buf;
  1113.     struct dev *dev;
  1114.     LONG error;
  1115.  
  1116.     dev=fh->block?fh->vol->dev:(struct dev *)fh->vol;
  1117.     error=read_block_chk(ffsbase,dev,&block,fh->block);
  1118.     if(error)
  1119.         return error;
  1120.     bpb=fh->vol->id==ID_DOS_DISK?fh->vol->bsize-24:fh->vol->bsize;
  1121.     total=EC(block->data->fb_size);
  1122.     touch_read(dev,block);
  1123.     pos=fh->blocknr*bpb+fh->index;
  1124.     rest=total>pos?total-pos:0;
  1125.     num=num>rest?rest:num;
  1126.     size=bpb-fh->index;
  1127.     while(num)
  1128.     {
  1129.         if(size>num)
  1130.             size=num;
  1131.         if(!fh->current)
  1132.         {
  1133.             fh->current=fh->block;
  1134.             rest=fh->blocknr;
  1135.             while(rest--)
  1136.             {
  1137.                 error=read_block_chk(ffsbase,dev,&block,fh->current);
  1138.                 if(error)
  1139.                     return error;
  1140.                 fh->current=EC(block->data->fb_extend);
  1141.                 touch_read(dev,block);
  1142.             }
  1143.         }
  1144.         error=read_block_chk(ffsbase,dev,&block,fh->current);
  1145.         if(error)
  1146.             return error;
  1147.         touch_read(dev,block);
  1148.         if(fh->vol->id==ID_DOS_DISK)
  1149.         {
  1150.             error=read_block_chk(ffsbase,dev,&block,EC(block->data->fb_data[HASHSIZE-1-fh->blocknr%(HASHSIZE)]));
  1151.             if(error)
  1152.                 return error;
  1153.             CopyMem((STRPTR)(block->data->fb_data)+fh->index,buffer,size);
  1154.         }else
  1155.         {
  1156.             error=get_block(ffsbase,dev,&block,EC(block->data->fb_data[fh->blocknr%(HASHSIZE)]));
  1157.             if(error)
  1158.                 return error;
  1159.             CopyMem((STRPTR)(block->data)+fh->index,buffer,size);
  1160.         }
  1161.         touch_read(dev,block);
  1162.         buffer+=size;
  1163.         num-=size;
  1164.         fh->index+=size;
  1165.         if(fh->index==bpb)
  1166.         {
  1167.             fh->index=0;
  1168.             fh->blocknr++;
  1169.         }
  1170.         if(!fh->blocknr%(HASHSIZE))
  1171.         {
  1172.             error=read_block_chk(ffsbase,dev,&block,fh->current);
  1173.             if(error)
  1174.                 return error;
  1175.             fh->current=EC(block->data->fb_extend);
  1176.             touch_read(dev,block);
  1177.         }
  1178.         size=bpb;
  1179.     }
  1180.     *numbytes=buffer-(STRPTR)buf;
  1181.     return 0;
  1182. }
  1183.  
  1184. static LONG free_lock(struct ffsbase *ffsbase, struct fh *fh)
  1185. {
  1186.     Remove((struct Node *)fh);
  1187.     FreeMem(fh,sizeof(struct fh));
  1188.     /* TODO: Dismount removed and unused disk */
  1189.     return 0;
  1190. }
  1191.  
  1192. static LONG create_dir(struct ffsbase *ffsbase, struct fh **fh, STRPTR name, ULONG protect)
  1193. {
  1194.     struct cinfo *block;
  1195.     struct dev *dev;
  1196.     struct fh *new;
  1197.     LONG error;
  1198.     
  1199.     dev=(*fh)->block?(*fh)->vol->dev:(struct dev *)(*fh)->vol;
  1200.  
  1201.     error=findname(ffsbase,*fh,&name,&block);
  1202.     if(!error)
  1203.         return ERROR_OBJECT_EXISTS;
  1204.     if(error!=ERROR_OBJECT_NOT_FOUND)
  1205.         return error;
  1206.     new=AllocMem(sizeof(struct fh),MEMF_CLEAR);
  1207.     if(new!=NULL)
  1208.     {
  1209.         error=create_object(ffsbase,dev,&new->block,block,name,protect,ST_USERDIR);
  1210.         if(!error)
  1211.         {
  1212.             new->vol=dev->vol;
  1213.             new->locked=1;
  1214.             AddHead((struct List *)&dev->vol->dirs,(struct Node *)new);
  1215.             *fh=new;
  1216.             return 0;
  1217.         }
  1218.         FreeMem(new,sizeof(struct fh));
  1219.     }
  1220.     return error;
  1221. }
  1222.  
  1223. static const ULONG sizes[]=
  1224. { 0, offsetof(struct ExAllData,ed_Type), offsetof(struct ExAllData,ed_Size),
  1225.   offsetof(struct ExAllData,ed_Prot), offsetof(struct ExAllData,ed_Days),
  1226.   offsetof(struct ExAllData,ed_Comment), offsetof(struct ExAllData,ed_OwnerUID),
  1227.   sizeof(struct ExAllData)
  1228. }; 
  1229.  
  1230. static LONG examine_fib(struct ffsbase *ffsbase, struct dev *dev, ULONG block, struct ExAllData *ead, ULONG size, ULONG type)
  1231. {
  1232.     struct cinfo *file;
  1233.     STRPTR next, end, name;
  1234.     ULONG l;
  1235.     LONG error;
  1236.     if(type>ED_OWNER)
  1237.         return ERROR_BAD_NUMBER;
  1238.     next=(STRPTR)ead+sizes[type];
  1239.     end=(STRPTR)ead+size;
  1240.     error=read_block_chk(ffsbase,dev,&file,block);
  1241.     if(error)
  1242.     return error;
  1243.     touch_read(dev,file);
  1244.     switch(type)
  1245.     {
  1246.     case ED_OWNER:
  1247.         ead->ed_OwnerUID=EC(file->data->fb_owner)>>16;
  1248.         ead->ed_OwnerGID=EC(file->data->fb_owner)&0xffff;
  1249.     case ED_COMMENT:
  1250.         name=(STRPTR)(file->data->fb_comment);
  1251.         l=*name++;
  1252.         if(l)
  1253.         {
  1254.             ead->ed_Comment=next;
  1255.             if(next+l+1>=end)
  1256.                 return ERROR_BUFFER_OVERFLOW;
  1257.             do
  1258.                 *next++=*name++;
  1259.             while(--l);
  1260.             *next++='\0';
  1261.         }else
  1262.             ead->ed_Comment=NULL;
  1263.     case ED_DATE:
  1264.         ead->ed_Days=EC(file->data->fb_days);
  1265.         ead->ed_Mins=EC(file->data->fb_mins);
  1266.         ead->ed_Ticks=EC(file->data->fb_ticks);
  1267.     case ED_PROTECTION:
  1268.         ead->ed_Prot=EC(file->data->fb_protect)^0xf;
  1269.     case ED_SIZE:
  1270.         ead->ed_Size=EC(file->data->fb_size);
  1271.     case ED_TYPE:
  1272.         ead->ed_Type=EC(file->data->fb_sectype);
  1273.     case ED_NAME:
  1274.         name=(STRPTR)(file->data->fb_name);
  1275.         l=*name++;
  1276.         ead->ed_Name=next;
  1277.         if(next+l+1>=end)
  1278.             return ERROR_BUFFER_OVERFLOW;
  1279.         if(l)
  1280.             do
  1281.                 *next++=*name++;
  1282.             while(--l);
  1283.         *next++='\0';
  1284.     case 0:
  1285.         ead->ed_Next=(struct ExAllData *)(((ULONG)next+AROS_PTRALIGN-1)&~(AROS_PTRALIGN-1));
  1286.     }
  1287.     return 0;
  1288. }
  1289.  
  1290. static LONG examine(struct ffsbase *ffsbase, struct fh *fh, struct ExAllData *ead, ULONG size, ULONG type)
  1291. {
  1292.     return examine_fib(ffsbase,fh->vol->dev,fh->block,ead,size,type);
  1293. }
  1294.  
  1295. static LONG examine_all(struct ffsbase *ffsbase, struct fh *dir, struct ExAllData *ead, ULONG size, ULONG type)
  1296. {
  1297.     STRPTR end;
  1298.     struct ExAllData *last=NULL;
  1299.     struct cinfo *block;
  1300.     struct dev *dev;
  1301.     LONG error;
  1302.     dev=dir->block?dir->vol->dev:(struct dev *)dir->vol;
  1303.     end=(STRPTR)ead+size;
  1304.     error=read_block_chk(ffsbase,dev,&block,dir->block);
  1305.     if(error)
  1306.     return error;
  1307.     touch_read(dev,block);
  1308.     if(block->data->fb_sectype!=EC(ST_USERDIR)&&
  1309.        block->data->fb_sectype!=EC(ST_ROOT))
  1310.         return ERROR_OBJECT_WRONG_TYPE;
  1311.     if(!dir->blocknr)
  1312.         for(;dir->index<HASHSIZE;dir->index++)
  1313.             if(block->data->fb_hashtable[dir->index])
  1314.             {
  1315.                 dir->blocknr=EC(block->data->fb_hashtable[dir->index]);
  1316.                 break;
  1317.             }
  1318.     if(dir->index>=HASHSIZE)
  1319.     {
  1320.         dir->index=0;
  1321.         return ERROR_NO_MORE_ENTRIES;
  1322.     }
  1323.     do
  1324.     {
  1325.         error=examine_fib(ffsbase,dev,dir->blocknr,ead,end-(STRPTR)ead,type);
  1326.         if(error==ERROR_BUFFER_OVERFLOW)
  1327.         {
  1328.             if(last==NULL)
  1329.                 return error;
  1330.             last->ed_Next=NULL;
  1331.             return 0;
  1332.         }
  1333.         last=ead;
  1334.         ead=ead->ed_Next;
  1335.         error=read_block_chk(ffsbase,dev,&block,dir->blocknr);
  1336.         if(error)
  1337.              return error;
  1338.         touch_read(dev,block);
  1339.         dir->blocknr=EC(block->data->fb_nexthash);
  1340.         if(!dir->blocknr)
  1341.         {
  1342.             error=read_block_chk(ffsbase,dev,&block,dir->block);
  1343.             if(error)
  1344.                  return error;
  1345.             touch_read(dev,block);
  1346.             for(dir->index++;dir->index<HASHSIZE;dir->index++)
  1347.                 if(block->data->fb_hashtable[dir->index])
  1348.                 {
  1349.                     dir->blocknr=EC(block->data->fb_hashtable[dir->index]);
  1350.                     break;
  1351.                 }
  1352.         }
  1353.     }while(dir->index<HASHSIZE);
  1354.     last->ed_Next=NULL;
  1355.     return 0;
  1356. }
  1357.  
  1358. void deventry(struct ffsbase *ffsbase)
  1359. {
  1360.     struct IOFileSys *iofs;
  1361.     LONG error=0;
  1362.     struct vol *vol;
  1363.     /*
  1364.         Init device ports. AllocSignal() cannot fail because this is a
  1365.     freshly created task with all signal bits still free. 
  1366.     */
  1367.     ffsbase->port.mp_SigBit=AllocSignal(-1);
  1368.     ffsbase->port.mp_Flags=PA_SIGNAL;
  1369.     ffsbase->dport.mp_SigBit=AllocSignal(-1);
  1370.     ffsbase->dport.mp_Flags=PA_SIGNAL;
  1371.  
  1372.     /* Get and process the messages. */
  1373.     for(;;)
  1374.     {
  1375.         while((iofs=(struct IOFileSys *)GetMsg(&ffsbase->port))!=NULL)
  1376.         {
  1377.             switch(iofs->IOFS.io_Command)
  1378.             {
  1379.                 case (UWORD)-1:
  1380.                     error=mount(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
  1381.                         (STRPTR)iofs->io_Args[0], iofs->io_Args[1],
  1382.                         (IPTR *)iofs->io_Args[2]);
  1383.             iofs->io_DosError=error;
  1384.             if(!error)
  1385.             (void)disk_change(ffsbase,(struct dev *)((struct fh *)iofs->IOFS.io_Unit)->vol);
  1386.             PutMsg(&ffsbase->rport,&iofs->IOFS.io_Message);
  1387.             continue;
  1388.         case FSA_OPEN:
  1389.             error=open(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
  1390.                           (STRPTR)iofs->io_Args[0], iofs->io_Args[1]);
  1391.             break;
  1392.         case FSA_OPEN_FILE:
  1393.             error=open_file(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
  1394.                           (STRPTR)iofs->io_Args[0], iofs->io_Args[1],
  1395.                           iofs->io_Args[2]);
  1396.             break;
  1397.         case FSA_READ:
  1398.             error=read(ffsbase,(struct fh *)iofs->IOFS.io_Unit,
  1399.                      (APTR)iofs->io_Args[0], &iofs->io_Args[1]);
  1400.             break;
  1401.         case FSA_CLOSE:
  1402.             error=free_lock(ffsbase,(struct fh *)iofs->IOFS.io_Unit);
  1403.             break;
  1404.         case FSA_CREATE_DIR:
  1405.             error=create_dir(ffsbase,(struct fh **)&iofs->IOFS.io_Unit,
  1406.                     (STRPTR)iofs->io_Args[0], iofs->io_Args[1]);
  1407.             break;
  1408.         case FSA_EXAMINE:
  1409.             error=examine(ffsbase,(struct fh *)iofs->IOFS.io_Unit,
  1410.                           (struct ExAllData *)iofs->io_Args[0],
  1411.                           iofs->io_Args[1], iofs->io_Args[2]);
  1412.             break;
  1413.         case FSA_EXAMINE_ALL:
  1414.             error=examine_all(ffsbase,(struct fh *)iofs->IOFS.io_Unit,
  1415.                               (struct ExAllData *)iofs->io_Args[0],
  1416.                               iofs->io_Args[1], iofs->io_Args[2]);
  1417.             break;
  1418.         default:
  1419.             error=ERROR_NOT_IMPLEMENTED;
  1420.             break;
  1421.             }
  1422.             iofs->io_DosError=error;
  1423.             ReplyMsg(&iofs->IOFS.io_Message);
  1424.         }
  1425.         if(ffsbase->dlflag)
  1426.         {
  1427.             if(AttemptLockDosList(LDF_VOLUMES|LDF_WRITE)!=NULL)
  1428.             {
  1429.                 while((vol=(struct vol *)RemHead((struct List *)&ffsbase->removed))!=NULL)
  1430.                 {
  1431.                     (void)RemDosEntry(vol->dlist);
  1432.                     FreeDosEntry(vol->dlist);
  1433.                     FreeMem(vol,sizeof(struct vol));
  1434.                 }
  1435.                 while((vol=(struct vol *)RemHead((struct List *)&ffsbase->inserted))!=NULL)
  1436.                 {
  1437.                     AddHead((struct List *)&ffsbase->mounted,(struct Node *)vol);
  1438.                     (void)AddDosEntry(vol->dlist);
  1439.                 }
  1440.                 UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  1441.                 ffsbase->dlflag=0;
  1442.             }else
  1443.             {
  1444.                 /* Wait some time then try again */
  1445.                 Delay(TICKS_PER_SECOND/10);
  1446.                 continue;
  1447.             }
  1448.         }
  1449.         WaitPort(&ffsbase->port);
  1450.     }
  1451. }
  1452.  
  1453. const char end=0;
  1454.