code: mafs

ref: b3e875d7db45fca0cde9f4efa12872f61afc54d7
dir: /dat.h/

View raw version
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;

typedef	struct	Config	Config;
typedef	struct	Data	Data;
typedef	struct	Dentryhdr	Dentryhdr;
typedef	struct	Dentry	Dentry;
typedef	struct	Datahdr	Datahdr;
typedef	struct	Indirect	Indirect;
typedef	struct	Name	Name;
typedef	struct	Super	Super;
typedef	struct	Tlock	Tlock;
typedef	struct	User	User;
typedef struct	Aux Aux;

enum
{
	KiB	= 1024ULL,	/* Kibibytes */
	MiB	= KiB*KiB,	/* Mibibytes */
	GiB	= KiB*MiB,	/* Gibibytes */
	TiB	= KiB*GiB,	/* Tibibytes */

	Ngroups	= 32,	/* maximum number of groups an user can belong to */
	None	= 0,	/* user ID for "none" */
	Noworld	= 9999,	/* conventional id for "noworld" group */
	Userlen = 32,
	Servicelen = 128,
	Nfirst = 6,		/* length of name stored in Name */

	Nsec	= 1000ULL*1000*1000,
	Usec	= 1000ULL*1000,
	Msec	= 1000ULL,
	Nbkp	= 1,
	Nrefresh = 3*Nsec,

	/* for Dentry.flags and Data.flags */
	Fsys = 0x80,/* for flagging .n, .nl and .nle files. Dentry.flags */
	Fn	= 1,	/* .n Name index file format */
	Fe	= 2,	/* Binary extents file format. TODO we are using text extents now */

	In	= 0,	/* reli of .n file */
	Inl	= 1,	/* reli of .nl file */
	Inle= 2,	/* reli of .nle file */
	Nsys,
};

/*
 * fundamental constants and types of the implementation
 * changing any of these changes the layout on disk
 * The very first block (index = 0) has the magic written at offset 256.
 *
 * Trying to keep the Qpath the same as the directory entry block number
 * for the system files to help me identify numbers easily.
 *
 * derived constants
 * Nindperblock number of block pointers in a block
 */
enum {
	Blocksize	= 512ULL,	/* minimum data unit size */

	Maxdatablockunits = 2048,
	Nindperblock= (Blocksize-3*sizeof(u64))/sizeof(u64),/* number of pointers per block */
	Nu64perblock= (Blocksize/sizeof(u64)),		/* number of u64's in a block */
	Dpathidx	= (Blocksize/sizeof(u64) -1),	/* index of path in the last data block, last u64 */

	Ndblock	= 46,	/* number of direct blocks in a Dentry */
	Niblock	= 5,	/* maximum depth of indirect blocks, can increase it to 9 without issues */

	/* global block numbers. The bkp contents locations are calculated by ream() */
	Bdmagic	= 0,	/* block number of first block. Bmagic conflicts with bio.h */
	Bdconfig= 1,	/* block number of /a/config dentry and contents */
	Bdsuper	= 2,	/* block number of /a/super dentry and contents */

	Bda		= 3,	/* block number of /a directory */
	Bdanames= 4,	/* block number of /a dir names directory */
	Bdalnames= 5,	/* block number of /a dir long names directory */
	Bdalnamesextents= 6,	/* block number of /a dir long names extents directory */

	Bdusers	= 7,	/* block number of /a/users/ directory entry */
	Bdusersnames= 8,/* block number of /a/users/ directory names */
	Bduserslnames= 9,/* block number of /a/users/ directory long names */
	Bduserslnamesextents= 10,/* block number of /a/users/ directory long names extents */

					/* contents of blocks below change on use */ 
	Bdbkp	= 11,	/* block number of /a/bkp directory */
	Bdbkpnames= 12,	/* block number of /a/bkp directory names */
	Bdbkplnames= 13,/* block number of /a/bkp directory long names */
	Bdbkplnamesextents= 14,	/* block number of /a/bkp directory long names extents */

	Bdusersinuse = 15,	/* block number of /a/users/inuse dentry and contents */
	Bdfrees = 16,	/* block number of /a/frees dentry, text file of free extents */

					/* no user writes allowed on blocks below Bdctl */
	Bdctl	= 17,	/* block number of /a/ctl dentry, empty contents, virtual file */
	Bdusersstaging = 18,/* block number of /a/users/staging dentry */

	Bdroot	= 19,	/* block number of root directory */
	Bdrootnames	= 20,	/* block number of root directory names */
	Bdrootlnames	= 21,	/* block number of root directory long names */
	Bdrootlnamesextents	= 22,	/* block number of root directory long names extents */

	Nbused,	/* blocks used up by default */

	/* number of blocks used by the above and the backup blocks */
	Nminblocks = Nbused+(Nbkp*3),

	/* Qpnone is the Tag.path of free blocks/extents(Tfree),
		and zero'ed out dentry blocks */
	Qpnone		= 0,
	Qpconfig	= Bdconfig,	/* /a/config block Tag.qpath */
	Qpsuper		= Bdsuper,	/* /a/super block Tag.qpath */

	Qpa			= Bda,	/* /a */
	Qpanames	= Bdanames,	/* /a */
	Qpalnames	= Bdalnames,	/* /a */
	Qpalnamesextents= Bdalnamesextents,	/* /a */

	Qpusers		= Bdusers,	/* /a/users block Tag.qpath */
	Qpusersnames= Bdusersnames,	/* /a/users block Tag.qpath */
	Qpuserslnames= Bduserslnames,	/* /a/users block Tag.qpath */
	Qpuserslnamesextents= Bduserslnamesextents,	/* /a/users block Tag.qpath */

	Qpbkp		= Bdbkp,	/* /a/bkp block Tag.qpath */
	Qpbkpnames	= Bdbkpnames,	/* /a/bkp block Tag.qpath */
	Qpbkplnames	= Bdbkplnames,	/* /a/bkp block Tag.qpath */
	Qpbkplnamesextents= Bdbkplnamesextents,	/* /a/bkp block Tag.qpath */

	Qpusersinuse= Bdusersinuse,	/* /a/users/inuse block Tag.qpath */
	Qpfrees		= Bdfrees,	/* /a/frees block Tag.qpath */

				/* system qpaths */
	Qpmagic		= Bdrootlnamesextents+1,	/* magic block Tag.qpath, could use Bdroot butt this avoids confusion by keeping the block numbers and qpaths distinct */
	Qpconfig0,	/* /a/bkp/config.0 block Tag.qpath */
	Qpsuper0,	/* /a/bkp/super.0 block Tag.qpath */
	Qproot0,	/* /a/bkp/root.0 block Tag.qpath */

	Qproot	= 32,	/* /, so fscreate() and fswrite() can disallow any create's below */
	Qprootnames,
	Qprootlnames,
	Qprootlnamesextents,

	Qpctl,			/* /a/ctl */
	Qpusersstaging,	/* /a/users/staging block Tag.qpath */
	Nqidgen	= 64,

	/* check qpath for overflows - TODO, should be 2^64 */
	Maxqpath = 72057594037927936ULL, /* 2^56 */

	Nthdirty = 9,	/* dirty byte is the 9th byte in the Tag */
};

#pragma pack on
/* DONT TOUCH, this is the disk structure */
/* no access time */
struct Dentryhdr
{
	u8 tag;
	u8 flags;		/* attributes (names extents, names - hide system files) */
	s16 uid;
	s16 gid;
	s16 muid;		/* 8 */
	u64 size;		/* 0 for directories. For files, size in bytes of the content - 16 */
	u64 pdblkno; 	/* block number of the parent directory entry. 0 for root. - 24 */
	u64 pqpath; 	/* parent qid.path - 32 */
	u64 preli; 		/* my reli in my parent's directory entry - 40 */
	u64 mtime;		/* modified time in nano seconds from epoch - 48 */
	u64 qpath;		/* unique identifier Qid.path 56 */
	u32 version;	/* Qid.version 60 */
	u32 mode;		/* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 64 */
};
struct Datahdr
{
	u8 tag;
	u8 flags;	/* 0 for text, 1 for In Name file, 2 for extents */
	u16 len;
	u64 dblkno;	/* block number of the directory entry */
};
#pragma pack off

enum {
	/* size of identifiers used in a Tdata block */
	Ddataidssize = sizeof(Datahdr) +sizeof(u64 /* trailing path */),
	/* max possible size of data that can be stuffed into a Dentry */
	Ddatasize = Blocksize -sizeof(Dentryhdr) -sizeof(u64 /* trailing path */),
	Maxdatablocksize = Maxdatablockunits*Blocksize -Ddataidssize,
};

#pragma pack on
/* DONT TOUCH, these are all disk structures */
struct Super
{
	u64 qidgen;	/* generator for unique ids. starts from 1024. */
	u64 fsok;	/* fsck status, using 64 bits to keep it all aligned */
};
struct Dentry
{
	Dentryhdr;
	union
	{
		struct
		{
			u64 dblocks[Ndblock];	/* direct blocks. */
									/* List of Tdata block numbers for files and
										Tdentry block numbers for directories */
			u64 iblocks[Niblock];	/* indirect blocks */
		};
		Super;

		/* when size <= Ddatasize, store the data here itself */
		s8 buf[Ddatasize];
	};
	u64 path;	/* same as qid.path */
};
struct Indirect
{
	u8 tagi;	/* the suffix i to avoid union complaining about ambiguous fields */
	u8 pad[7];	/* unused, to align to a multiple of 8 */
	u64 dblkno;	/* block number of the directory entry */
	u64 bufa[Nindperblock];
	u64 pathi;	/* same as qid.path */
};
struct Data		/* used to unmarshall the disk contents */
{
	Datahdr;
	u8 buf[1];	/* upto Maxdatablocksize, followed by u64 qid.path */
	/* u64 path; same as qid.path at the end of the data content - check consistency */
};
struct Name
{
	u16	namelen;
	s8 name[Nfirst];	/* first 6 bytes. If longer, use noffset */
	u64 noffset;		/* offset where the name is stored in .nl - long names file */
};
#pragma pack off

/*
 * array of qids that are locked
 */
struct Tlock
{
	u64 time;
	u64 qpath;
	u64 dblkno;
	Tlock *prev, *next;
};

struct Aux
{
	u64 dblkno; /* directory entry absolute block number */
	u64 pdblkno;/* block number of my parent's directory entry */
	u64 pqpath;/* block number of my parent's directory entry */
	u64 preli;	/* my relative index in the parent's directory entry */
	u8 flags;	/* corresponds to Dentry.flags and Data.flags */
	u16 uid;
	u8 tlocked;	/* for exclusive use files, flag to indicate lock */
	u64 dri;	/* directory index while reading a directory */
	s8 *ctlmsg;
	u32 nctlmsg;
	/* u64 lastreadahead; TODO */
};

/*
	every user is also a group with one user.
 */
struct User
{
	s16 id;		/* user id */
	s16 lid;	/* id of the leader of group */
	char name[Userlen];	/* user name */
	s16 *members;/* list of member id's belonging to this group */
	int nmembers;/* number of members in this group */
	int nalloc;	/* allocated space members */
	User *prev, *next;	/* linked list sorted by id */
};

/* storing this in ascii to the Bdconfig block */
struct Bkp
{
	u64 srcbno;		/* source of the backup */
	u64 dest[Nbkp];	/* destinations written to */
};
struct Config
{
	u64 size;	/* size from dirfstat */
	u64 nblocks; /* size in blocks */
	struct Bkp config;
	struct Bkp super;
	struct Bkp root;
	char service[Servicelen];
};

enum
{
	Nworks = 1024,	/* make this a parameter? */
	Nworkers = 32,	/* make this a parameter? */
	Nuserserrmsg = 64,
};

/*
 * error codes generated from the file server
 */
enum
{
	Eaccess = 1,
	Ealloc,
	Eauth,
	Eauthmsg,
	Ebadname,
	Ebadspc,
	Ebadu,
	Ebroken,
	Echar,
	Econvert,
	Ecount,
	Edexist,
	Edir1,
	Edir2,
	Edirty,
	Edot,
	Eempty,
	Eentry,
	Eexist,
	Efid,
	Efidinuse,
	Efull,
	Einval,
	Einvread,
	Einvwrite,
	Einvusers,
	Elocked,
	Emode,
	Ename,
	Enomem,
	Enotd,
	Enotdir,
	Enotfound,
	Enotg,
	Enotl,
	Enotm,
	Enotu,
	Enotw,
	Enouser,
	Enousers,
	Eoffset,
	Eopen,
	Eperm,
	Ephase,
	Eqid,
	Eqidmode,
	Eronly,
	Ersc,
	Eshutdown,
	Esystem,
	Etoolong,
	Ewalk,
	MAXERR
};

/*
 * tags on block
 */
/* DONT TOUCH, this is in disk structures */
/* the first 512 bytes holds the magic.
	Not bothering with a tag for 1 Unit. Use Tdentry for that.
 */
/* also, the order from Tdata to Tmaxind is exploited in indirck() & isdirty() */
enum
{
	Tblank = 0,
	Tfree  = 0,	/* free block */
	Tnone  = 0,
	Tdata,		/* actual file contents */
	Tdentry,	/* directory entry, size = Dentrysize */
				/* Tdata & indirect blocks are last, to allow for greater depth */
	Tind0,		/* contains a list of Tdata block numbers for files
					and Tdentry block numbers for directories.*/
	Tind1,		/* contains a list of Tind0 block numbers */
	Tind2,		/* contains a list of Tind1 block numbers */
	Tind3,		/* contains a list of Tind1 block numbers */
	Tind4,		/* contains a list of Tind1 block numbers */
				/* gap for more indirect block depth in future.
					It can be put upto Tind7 without needing any code changes */
	Maxtind,	/* should be Tind0+Niblock */
	MAXTAG = Maxtind,

	Tmaxind = Maxtind - 1,
};

/*
 * flags to getbuf
 */
enum
{
	Breadonly	= 1,/* read the block, cannot write to it */
	Bwritable	= 0,
	Bfreshalloc = 1,/* newly allocated block, no contents on the disk */
	Bused 		= 0,/* has contents on the disk */
};

#define SECOND(n) 	(n)
#define MINUTE(n)	(n*SECOND(60))
#define HOUR(n)		(n*MINUTE(60))
#define DAY(n)		(n*HOUR(24))
#define	TLOCK		MINUTE(5)

extern	char*	errstring[MAXERR];
extern	char	service[Servicelen];
extern	char	*tagnames[];
extern	char	*devfile;	/* device file path */
extern	int		devfd ;		/* device fd */

extern	int	writeallow;
extern	int	wstatallow;
extern	int	allownone;
extern	u8 readonly;
extern	u8 shuttingdown;
extern	u8 noauth;

/* used by panic() */
extern	char	*procname;

extern Config config;
extern char userserrmsg[Nuserserrmsg];
Config *parseconfig(s8 *cfg, Config *c);

typedef	struct	Errenv	Errenv;
struct Errenv		/* Error environment */
{
	jmp_buf label[16];
	u8 nlabel;
};
extern s8 err[ERRMAX];
extern Errenv **envpp;
void nexterror(void);
void error(s8 *fmt, ...);
extern void showerrenv(char *msg);
#define		poperror()	(*envpp)->nlabel--
/* #define		waserror()	(showerrenv("waserror before\n"), (*envpp)->nlabel++, setjmp((*envpp)->label[(*envpp)->nlabel-1])) */
#define		waserror()	((*envpp)->nlabel++, setjmp((*envpp)->label[(*envpp)->nlabel-1]))