/* chunks.h   -- low level allocation driver for xfiles *               which 
 * handles the allocation of 'disc' *               chunks including
 * extension of the virtual *               disc as necessary. */

#ifndef __chunks_h
#define __chunks_h

#include "kernel.h"

#define xFiles_TYPE              0xB23							/* for now             */
#define xFiles_SIG               0x4C494658						/* 'XFIL' or something */
#define xFiles_DIRSIG            0x79646E41						/* 'Andy' of course    */
#define xFiles_STRUCTUREVERSION  1
#define xFiles_DIRECTORYVERSION  1
#define xFiles_ALLOCATIONUNIT    1024							/* and why not? */
#define xFiles_WINDOWSIZE        16384							/* size of window buffer */
#define xFiles_NEWCHUNKS         100
#define xFiles_GROWDIRBY         20
#define xFiles_MAXNAME           256
#define xFiles_CHUNKCACHE        10								/* actually 5 seems OK, but... */

#ifndef BOOL
#define BOOL int
#ifndef FALSE
#define FALSE (1 == 0)
#endif
#ifndef TRUE
#define TRUE  (!FALSE)
#endif
#endif

/* Fundamental disc allocation record. Used ones contain an offset * into the 
 * image and size. Unused ones are chained together through * their offset
 * field (i.e. if the offset field is 1 the next free * chunk is number 1).
 * Since chunk zero can never be free a zero in * the offset field marks the
 * end of the free chain. */
typedef struct
{
	unsigned offset;
	unsigned size;
	unsigned usage;
	unsigned allocSize;

}
xFiles_chunk;

typedef struct
{
	unsigned cnkNum;
	xFiles_chunk chunk;

}
xFiles_chunkCacheItem;

typedef struct
{
	unsigned sig;
	unsigned hdrSize;											/* size of this structure                      */
	unsigned structureVersion;
	unsigned directoryVersion;

	xFiles_chunk chunkTable;									/* this record is duplicated in the chunkTable */
	unsigned rootChunk;											/* root directory                              */

	unsigned allocationUnit;									/* allocate space in multiples of this. can be */
	/* changed after file creation because it only */
	/* influences allocation: the existing image   */
	/* is valid regardless of allocationUnit size  */
	unsigned freeChunk;											/* Head of the free chunk list                 */

	unsigned waste;												/* Amount of wasted space in the image         */

}
xFiles_header;

typedef struct xFiles_listItem
{
	struct xFiles_listItem *prev;
	struct xFiles_listItem *next;

}
xFiles_listItem;

typedef struct
{
	xFiles_listItem *head, *tail;

}
xFiles_list;

/* Flags for an image */

enum
{
	xFiles_fNeedTruncate = 0x0001
};

/* Memory stuff */

typedef struct
{
	xFiles_listItem li;											/* Must be first item */

	int fileHandle;												/* OS filehandle associated which this image is open on */
	BOOL readOnly;												/* True if the file is readonly                         */
	BOOL compacting;											/* True during compaction                               */
	int lastCompact;											/* Time of last compaction                              */

	xFiles_list openList;										/* List of open files on this image                     */

	xFiles_header fileHeader;									/* convenient */

	/* Random replacement chunk cache */

	xFiles_chunkCacheItem chunkCache[xFiles_CHUNKCACHE];
	int cacheUsed;

	unsigned fileSize;											/* cached file size */

	unsigned flags;

}
xFiles_info;

typedef struct
{
	unsigned sig;												/* 'Andy' of course! */
	unsigned parent;											/* 0 for root */
	unsigned size, used;

}
xFiles_dirHeader;

/* There's a dirHash for each directory entry. It's not really a hash, just
 * the * first four characters of the name (duplicated in the real entry) and 
 * an * offset to the actual entry. */

typedef struct
{
	char nameStart[4];
	unsigned entryPos;
	unsigned node;												/* chunk number where this entry may be found */

}
xFiles_dirHash;

typedef enum
{
	xFiles_meRead = 0x001,
	xFiles_meWrite = 0x002,
	xFiles_locked = 0x008,
	xFiles_youRead = 0x010,
	xFiles_youWrite = 0x020,

	/* Now our private ones */

	xFiles_isDir = 0x100

}
xFiles_attr;

/* Here's the actual directory entry. The name, which can be any length,
 * follows * the entry and is NULL terminated. The next entry is at the next
 * word boundary */

typedef struct
{
	unsigned load;
	unsigned exec;
	unsigned size;												/* can be found from node but this is quicker */
	xFiles_attr attr;

	unsigned nameLen;

	/* Name follows */

}
xFiles_dirEntry;

/* Open file information structure */

typedef struct xFiles_fileInfo
{
	xFiles_listItem li;											/* Must be first item */

	int fileSwitchHandle;
	xFiles_info *pOwner;
	unsigned cnkNum;
	unsigned parentDir;											/* directory chunk */
	int fileSize;

}
xFiles_fileInfo;

extern void *xFiles_windowBuffer;								/* shared by all and sundry */
extern int xFiles_windowBufferSize;
extern xFiles_list xFiles_openFiles;
extern void *wsp;
extern int xFiles_Threaded;

unsigned xFiles_chunkAddress(xFiles_info * pInfo, unsigned cnkNum);
unsigned xFiles_roundUp(xFiles_info * pInfo, unsigned pos);
unsigned xFiles_roundDown(xFiles_info * pInfo, unsigned pos);
_kernel_oserror *xFiles_InitCache(unsigned size);
_kernel_oserror *xFiles_FlushFileInfo(xFiles_info * pInfo);
_kernel_oserror *xFiles_buildNewFilesystem(xFiles_info * pInfo);
_kernel_oserror *xFiles_claimBuffer(int notBiggerThan);
_kernel_oserror *xFiles_releaseBuffer(void);
_kernel_oserror *xFiles_getChunkInfo(xFiles_info * pInfo, unsigned cnkNum, xFiles_chunk * pChunk);
_kernel_oserror *xFiles_getLength(xFiles_info * pInfo, unsigned *pLength);
_kernel_oserror *xFiles_makeFreeChunks(xFiles_info * pInfo);
_kernel_oserror *xFiles_moveToEnd(xFiles_info * pInfo, unsigned cnkNum);
_kernel_oserror *xFiles_newChunk(xFiles_info * pInfo, unsigned *pCnkNum);
_kernel_oserror *xFiles_OpenImage(xFiles_info * pInfo);
_kernel_oserror *xFiles_CloseImage(xFiles_info * pInfo);
_kernel_oserror *xFiles_read(xFiles_info * pInfo, void *pBuffer, unsigned pos, unsigned size);
_kernel_oserror *xFiles_setChunkInfo(xFiles_info * pInfo, unsigned cnkNum, const xFiles_chunk * pChunk);
_kernel_oserror *xFiles_setLength(xFiles_info * pInfo, unsigned Length);
_kernel_oserror *xFiles_squashFile(xFiles_info * pInfo, BOOL force);
_kernel_oserror *xFiles_updateHeader(xFiles_info * pInfo);
_kernel_oserror *xFiles_write(xFiles_info * pInfo, void *pBuffer, unsigned pos, unsigned size);
_kernel_oserror *xFiles_erase(xFiles_info * pInfo, unsigned pos, unsigned size);

_kernel_oserror *xFiles_freeChunk(xFiles_info * pInfo, unsigned cnkNum);
_kernel_oserror *xFiles_setChunkSize(xFiles_info * pInfo, unsigned cnkNum, unsigned size);
_kernel_oserror *xFiles_moveBlock(xFiles_info * pInfo, unsigned to, unsigned from, int size);
_kernel_oserror *xFiles_midExtend(xFiles_info * pInfo, unsigned cnkNum, int pos, int by);
_kernel_oserror *xFiles_midExtendDirectory(xFiles_info * pInfo, unsigned dirObject, int pos, int by);

_kernel_oserror *xFiles_readChunk(xFiles_info * pInfo, void *pBuffer, unsigned cnkNum, unsigned pos,
		unsigned size);
_kernel_oserror *xFiles_writeAndGrow(xFiles_info * pInfo, void *pBuffer, unsigned cnkNum, unsigned pos,
		unsigned size);
_kernel_oserror *xFiles_writeChunk(xFiles_info * pInfo, void *pBuffer, unsigned cnkNum, unsigned pos,
		unsigned size);

_kernel_oserror *xFiles_getDirHeader(xFiles_info * pInfo, unsigned dirObject, xFiles_dirHeader * pHdr);
_kernel_oserror *xFiles_setDirHeader(xFiles_info * pInfo, unsigned dirObject, const xFiles_dirHeader
		* pHdr);
_kernel_oserror *xFiles_cDir(xFiles_info * pInfo, unsigned parent, unsigned *pCnkNum);
_kernel_oserror *xFiles_createDirEntry(xFiles_info * pInfo, unsigned dirObject, xFiles_dirHash * pDirHash,
		xFiles_dirEntry * pDirEnt, const char *pName);
_kernel_oserror *xFiles_makeSpaceInHashTable(xFiles_info * pInfo, unsigned dirObject);
_kernel_oserror *xFiles_relocateHashes(xFiles_info * pInfo, unsigned dirObject, int pos, int by);
_kernel_oserror *xFiles_dirLookup(xFiles_info * pInfo, unsigned dirObject, const char *pName, unsigned *pHashOffset,
		unsigned *pEntryOffset, xFiles_dirHash * pDirHash, xFiles_dirEntry * pDirEnt);
_kernel_oserror *xFiles_dirLookupByNode(xFiles_info * pInfo, unsigned dirObject, unsigned node, unsigned *pHashOffset,
		unsigned *pEntryOffset, xFiles_dirHash * pDirHash);
_kernel_oserror *xFiles_deleteDirEntry(xFiles_info * pInfo, unsigned dirObject, unsigned hashOffset);
_kernel_oserror *xFiles_parsePath(xFiles_info * pInfo, const char *pName, unsigned *pParent, unsigned *pHashOffset,
		unsigned *pEntryOffset, xFiles_dirHash * pDirHash, xFiles_dirEntry * pDirEnt, BOOL excludeLeaf);

_kernel_oserror *xFiles_Commit(xFiles_info * pInfo);
_kernel_oserror *xFiles_Truncate(xFiles_info * pInfo);
_kernel_oserror *xFiles_Ticker(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_WriteBehind(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_Flush(void);
void xFiles_Tidy(void);

/* List stuff */

void xFiles_InitItem(xFiles_listItem * pItem);
void xFiles_InitList(xFiles_list * pList);
void xFiles_AddAtHead(xFiles_list * pList, xFiles_listItem * pItem);
void xFiles_AddAtTail(xFiles_list * pList, xFiles_listItem * pItem);
void xFiles_Remove(xFiles_list * pList, xFiles_listItem * pItem);

/* Compaction routine */

_kernel_oserror *xFiles_Compact(xFiles_info * pInfo);

/***************************************************************************************/
/* */
/* Exported FS entry points
 *         */
/* */
/***************************************************************************************/

/* Errors which are defined in error.s */

extern _kernel_oserror xFiles_BadPermission;
extern _kernel_oserror xFiles_CantFake;
extern _kernel_oserror xFiles_NoMemory;
extern _kernel_oserror xFiles_ImageCorrupt;
extern _kernel_oserror xFiles_Truncated;
extern _kernel_oserror xFiles_Outside;
extern _kernel_oserror xFiles_BrokenDir;
extern _kernel_oserror xFiles_BadDirMark;
extern _kernel_oserror xFiles_OutOfRange;
extern _kernel_oserror xFiles_NotImplemented;
extern _kernel_oserror xFiles_NotFound;
extern _kernel_oserror xFiles_NotADir;
extern _kernel_oserror xFiles_NotAFile;
extern _kernel_oserror xFiles_Locked;
extern _kernel_oserror xFiles_BufferInUse;
extern _kernel_oserror xFiles_DirNotEmpty;
extern _kernel_oserror xFiles_LostTrack;
extern _kernel_oserror xFiles_IsOpen;

_kernel_oserror *xFiles_Open(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_GetBytes(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_PutBytes(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_Args(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_Close(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_File(_kernel_swi_regs * regs);
_kernel_oserror *xFiles_Func(_kernel_swi_regs * regs);

#endif
