ref: 1a4e1fc2e52ab80b55ef0d7fdccca973267fb4cc
dir: /dat.h/
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 Metadata Metadata; typedef struct Metadataunit Metadataunit; typedef struct Dentryhdr Dentryhdr; typedef struct Dentry Dentry; typedef struct Datahdr Datahdr; typedef struct Indirect Indirect; 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, Nsec = 1000ULL*1000*1000, Usec = 1000ULL*1000, Msec = 1000ULL, Nbkp = 1, Nrefresh = 3*Nsec, }; /* * 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 */ Metadataunits = 2, Metadatablocksize = Metadataunits*Blocksize, /* Keep the original and a copy together */ 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 */ Namelen = 127, /* maximum length of a file name, calculated manually */ Ndblock = 32, /* number of direct blocks in a Dentry */ Niblock = 5, /* maximum depth of indirect blocks, can increase it to 8 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= 2, /* block number of /adm/config dentry and contents */ Bdsuper = 4, /* block number of /adm/super dentry and contents */ Bdadm = 6, /* block number of /adm directory */ Bdusers = 8, /* block number of /adm/users/ dentry */ /* contents of blocks below change on use */ Bdbkp = 10, /* block number of /adm/bkp directory */ Bdusersinuse = 12, /* block number of /adm/users/inuse dentry and contents */ Bdfrees = 14, /* block number of /adm/frees dentry, text file of free extents */ /* no user writes allowed on blocks below Bdctl */ Bdctl = 16, /* block number of /adm/ctl dentry, empty contents, virtual file */ Bdusersstaging = 18,/* block number of /adm/users/staging dentry */ Bdroot = 20, /* block number of root directory */ Nbused = Bdroot+2, /* blocks used up by default */ /* number of blocks used by the above and the backup blocks */ Nminblocks = Nbused+(Metadataunits*Nbkp*3), /* Qpnone is the Tag.path of free blocks/extents(Tfree), and zero'ed out dentry blocks */ Qpnone = 0, Qpconfig = Bdconfig, /* /adm/config block Tag.qpath */ Qpsuper = Bdsuper, /* /adm/super block Tag.qpath */ Qpadm = Bdadm, /* /adm */ Qpusers = Bdusers, /* /adm/users block Tag.qpath */ Qpbkp = Bdbkp, /* /adm/bkp block Tag.qpath */ Qpusersinuse = Bdusersinuse, /* /adm/users/inuse block Tag.qpath */ Qpfrees = Bdfrees, /* /adm/frees block Tag.qpath */ Qpctl = Bdctl, /* /adm/ctl */ Qpusersstaging = Bdusersstaging,/* /adm/users/staging block Tag.qpath */ Qproot = Bdroot, /* /, so fscreate() can disallow any create's below */ /* system qpaths */ Qpmagic = 1, /* magic block Tag.qpath */ Qpconfig0 = 3, /* /adm/bkp/config.0 block Tag.qpath */ Qpsuper0 = 5, /* /adm/bkp/super.0 block Tag.qpath */ Qproot0 = 21, /* /adm/bkp/root.0 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 verd; 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. Will be 0 for root. - 24 */ u64 pqpath; /* parent qid.path - 32 */ u64 mtime; /* modified time in nano seconds from epoch - 40 */ u64 qpath; /* unique identifier Qid.path 48 */ u32 version; /* Qid.version 52 */ u32 mode; /* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 56 */ u8 namelen; /* store name as a counted string 57 */ s8 name[Namelen]; /* Namelen = 127 - 184*/ }; struct Datahdr { u8 tag; u8 unused; /* for alignment and future use */ 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 <= Dentrysize-184-sizeof(Tag), 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 veri; u8 pad[6]; /* unused, to align to a multiple of 8 */ u64 dblkno; /* block number of the directory entry */ u64 bufa[Nindperblock]; u64 path; /* same as qid.path */ }; struct Metadataunit { union { Indirect; Dentry; }; }; struct Metadata { union { Indirect i[2]; Dentry d[2]; }; }; 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 */ }; #pragma pack off /* * array of qids that are locked */ struct Tlock { u64 time; u64 qpath; u64 dblkno; Tlock *prev, *next; }; struct Aux { u64 dblkno; /* dentry absolute block number */ u16 uid; u8 tlocked; /* for exclusive use files, flag to indicate lock */ u64 dri; /* directory index while reading a directory */ /* 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[Namelen]; }; enum { Nworks = 1024, /* make this a parameter? */ Nworkers = 8 /* 32 */, /* make this a parameter? */ Nlru = 32, Nuserserrmsg = 64, }; /* * error codes generated from the file server */ enum { Eaccess = 1, Ealloc, Eauth, Eauthmsg, Ebadname, Ebadspc, Ebadu, Ebroken, Echar, Econvert, Ecount, Edir1, Edir2, Edirty, Edot, Eempty, Eentry, Eexist, Efid, Efidinuse, Efull, Einval, Elocked, Emode, Ename, Enomem, Enotd, Enotdir, Enotg, Enotl, Enotm, Enotu, Enotw, Eoffset, Eopen, Eperm, Ephase, Eqid, Eqidmode, Eronly, Ersc, Eshutdown, Esystem, Etoolong, Einvusers, Enousers, 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[Namelen]; 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);