summaryrefslogtreecommitdiff
path: root/mkfs/mkfs.c
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
committerRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
commit5753553213df8f9de851adb68377db43faecb91f (patch)
tree3b629ff54897fca414146677532cb459a2ed11ba /mkfs/mkfs.c
parent91ba81110acd3163f7de3580b677eece0c57f5e7 (diff)
downloadxv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.gz
xv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.bz2
xv6-labs-5753553213df8f9de851adb68377db43faecb91f.zip
separate source into kernel/ user/ mkfs/
Diffstat (limited to 'mkfs/mkfs.c')
-rw-r--r--mkfs/mkfs.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c
new file mode 100644
index 0000000..246a4e2
--- /dev/null
+++ b/mkfs/mkfs.c
@@ -0,0 +1,305 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define stat xv6_stat // avoid clash with host struct stat
+#include "kernel/types.h"
+#include "kernel/fs.h"
+#include "kernel/stat.h"
+#include "kernel/param.h"
+
+#ifndef static_assert
+#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
+#endif
+
+#define NINODES 200
+
+// Disk layout:
+// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
+
+int nbitmap = FSSIZE/(BSIZE*8) + 1;
+int ninodeblocks = NINODES / IPB + 1;
+int nlog = LOGSIZE;
+int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
+int nblocks; // Number of data blocks
+
+int fsfd;
+struct superblock sb;
+char zeroes[BSIZE];
+uint freeinode = 1;
+uint freeblock;
+
+
+void balloc(int);
+void wsect(uint, void*);
+void winode(uint, struct dinode*);
+void rinode(uint inum, struct dinode *ip);
+void rsect(uint sec, void *buf);
+uint ialloc(ushort type);
+void iappend(uint inum, void *p, int n);
+
+// convert to intel byte order
+ushort
+xshort(ushort x)
+{
+ ushort y;
+ uchar *a = (uchar*)&y;
+ a[0] = x;
+ a[1] = x >> 8;
+ return y;
+}
+
+uint
+xint(uint x)
+{
+ uint y;
+ uchar *a = (uchar*)&y;
+ a[0] = x;
+ a[1] = x >> 8;
+ a[2] = x >> 16;
+ a[3] = x >> 24;
+ return y;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i, cc, fd;
+ uint rootino, inum, off;
+ struct dirent de;
+ char buf[BSIZE];
+ struct dinode din;
+
+
+ static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
+
+ if(argc < 2){
+ fprintf(stderr, "Usage: mkfs fs.img files...\n");
+ exit(1);
+ }
+
+ assert((BSIZE % sizeof(struct dinode)) == 0);
+ assert((BSIZE % sizeof(struct dirent)) == 0);
+
+ fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if(fsfd < 0){
+ perror(argv[1]);
+ exit(1);
+ }
+
+ // 1 fs block = 1 disk sector
+ nmeta = 2 + nlog + ninodeblocks + nbitmap;
+ nblocks = FSSIZE - nmeta;
+
+ sb.magic = FSMAGIC;
+ sb.size = xint(FSSIZE);
+ sb.nblocks = xint(nblocks);
+ sb.ninodes = xint(NINODES);
+ sb.nlog = xint(nlog);
+ sb.logstart = xint(2);
+ sb.inodestart = xint(2+nlog);
+ sb.bmapstart = xint(2+nlog+ninodeblocks);
+
+ printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n",
+ nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
+
+ freeblock = nmeta; // the first free block that we can allocate
+
+ for(i = 0; i < FSSIZE; i++)
+ wsect(i, zeroes);
+
+ memset(buf, 0, sizeof(buf));
+ memmove(buf, &sb, sizeof(sb));
+ wsect(1, buf);
+
+ rootino = ialloc(T_DIR);
+ assert(rootino == ROOTINO);
+
+ bzero(&de, sizeof(de));
+ de.inum = xshort(rootino);
+ strcpy(de.name, ".");
+ iappend(rootino, &de, sizeof(de));
+
+ bzero(&de, sizeof(de));
+ de.inum = xshort(rootino);
+ strcpy(de.name, "..");
+ iappend(rootino, &de, sizeof(de));
+
+ for(i = 2; i < argc; i++){
+ // get rid of "user/"
+ char *shortname;
+ if(strncmp(argv[i], "user/", 5) == 0)
+ shortname = argv[i] + 5;
+ else
+ shortname = argv[i];
+
+ assert(index(shortname, '/') == 0);
+
+ if((fd = open(argv[i], 0)) < 0){
+ perror(argv[i]);
+ exit(1);
+ }
+
+ // Skip leading _ in name when writing to file system.
+ // The binaries are named _rm, _cat, etc. to keep the
+ // build operating system from trying to execute them
+ // in place of system binaries like rm and cat.
+ if(shortname[0] == '_')
+ shortname += 1;
+
+ inum = ialloc(T_FILE);
+
+ bzero(&de, sizeof(de));
+ de.inum = xshort(inum);
+ strncpy(de.name, shortname, DIRSIZ);
+ iappend(rootino, &de, sizeof(de));
+
+ while((cc = read(fd, buf, sizeof(buf))) > 0)
+ iappend(inum, buf, cc);
+
+ close(fd);
+ }
+
+ // fix size of root inode dir
+ rinode(rootino, &din);
+ off = xint(din.size);
+ off = ((off/BSIZE) + 1) * BSIZE;
+ din.size = xint(off);
+ winode(rootino, &din);
+
+ balloc(freeblock);
+
+ exit(0);
+}
+
+void
+wsect(uint sec, void *buf)
+{
+ if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){
+ perror("lseek");
+ exit(1);
+ }
+ if(write(fsfd, buf, BSIZE) != BSIZE){
+ perror("write");
+ exit(1);
+ }
+}
+
+void
+winode(uint inum, struct dinode *ip)
+{
+ char buf[BSIZE];
+ uint bn;
+ struct dinode *dip;
+
+ bn = IBLOCK(inum, sb);
+ rsect(bn, buf);
+ dip = ((struct dinode*)buf) + (inum % IPB);
+ *dip = *ip;
+ wsect(bn, buf);
+}
+
+void
+rinode(uint inum, struct dinode *ip)
+{
+ char buf[BSIZE];
+ uint bn;
+ struct dinode *dip;
+
+ bn = IBLOCK(inum, sb);
+ rsect(bn, buf);
+ dip = ((struct dinode*)buf) + (inum % IPB);
+ *ip = *dip;
+}
+
+void
+rsect(uint sec, void *buf)
+{
+ if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){
+ perror("lseek");
+ exit(1);
+ }
+ if(read(fsfd, buf, BSIZE) != BSIZE){
+ perror("read");
+ exit(1);
+ }
+}
+
+uint
+ialloc(ushort type)
+{
+ uint inum = freeinode++;
+ struct dinode din;
+
+ bzero(&din, sizeof(din));
+ din.type = xshort(type);
+ din.nlink = xshort(1);
+ din.size = xint(0);
+ winode(inum, &din);
+ return inum;
+}
+
+void
+balloc(int used)
+{
+ uchar buf[BSIZE];
+ int i;
+
+ printf("balloc: first %d blocks have been allocated\n", used);
+ assert(used < BSIZE*8);
+ bzero(buf, BSIZE);
+ for(i = 0; i < used; i++){
+ buf[i/8] = buf[i/8] | (0x1 << (i%8));
+ }
+ printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
+ wsect(sb.bmapstart, buf);
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+void
+iappend(uint inum, void *xp, int n)
+{
+ char *p = (char*)xp;
+ uint fbn, off, n1;
+ struct dinode din;
+ char buf[BSIZE];
+ uint indirect[NINDIRECT];
+ uint x;
+
+ rinode(inum, &din);
+ off = xint(din.size);
+ // printf("append inum %d at off %d sz %d\n", inum, off, n);
+ while(n > 0){
+ fbn = off / BSIZE;
+ assert(fbn < MAXFILE);
+ if(fbn < NDIRECT){
+ if(xint(din.addrs[fbn]) == 0){
+ din.addrs[fbn] = xint(freeblock++);
+ }
+ x = xint(din.addrs[fbn]);
+ } else {
+ if(xint(din.addrs[NDIRECT]) == 0){
+ din.addrs[NDIRECT] = xint(freeblock++);
+ }
+ rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
+ if(indirect[fbn - NDIRECT] == 0){
+ indirect[fbn - NDIRECT] = xint(freeblock++);
+ wsect(xint(din.addrs[NDIRECT]), (char*)indirect);
+ }
+ x = xint(indirect[fbn-NDIRECT]);
+ }
+ n1 = min(n, (fbn + 1) * BSIZE - off);
+ rsect(x, buf);
+ bcopy(p, buf + off - (fbn * BSIZE), n1);
+ wsect(x, buf);
+ n -= n1;
+ off += n1;
+ p += n1;
+ }
+ din.size = xint(off);
+ winode(inum, &din);
+}