mkfs/mkfs.c
303 lines
1#include <stdio.h>2#include <unistd.h>3#include <stdlib.h>4#include <string.h>5#include <fcntl.h>6#include <assert.h>78#define stat xv6_stat // avoid clash with host struct stat9#include "kernel/types.h"10#include "kernel/fs.h"11#include "kernel/stat.h"12#include "kernel/param.h"1314#ifndef static_assert15#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)16#endif1718#define NINODES 2001920// Disk layout:21// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]2223int nbitmap = FSSIZE/BPB + 1;24int ninodeblocks = NINODES / IPB + 1;25int nlog = LOGBLOCKS+1; // Header followed by LOGBLOCKS data blocks.26int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)27int nblocks; // Number of data blocks2829int fsfd;30struct superblock sb;31char zeroes[BSIZE];32uint freeinode = 1;33uint freeblock;343536void balloc(int);37void wsect(uint, void*);38void winode(uint, struct dinode*);39void rinode(uint inum, struct dinode *ip);40void rsect(uint sec, void *buf);41uint ialloc(ushort type);42void iappend(uint inum, void *p, int n);43void die(const char *);4445// convert to riscv byte order46ushort47xshort(ushort x)48{49 ushort y;50 uchar *a = (uchar*)&y;51 a[0] = x;52 a[1] = x >> 8;53 return y;54}5556uint57xint(uint x)58{59 uint y;60 uchar *a = (uchar*)&y;61 a[0] = x;62 a[1] = x >> 8;63 a[2] = x >> 16;64 a[3] = x >> 24;65 return y;66}6768int69main(int argc, char *argv[])70{71 int i, cc, fd;72 uint rootino, inum, off;73 struct dirent de;74 char buf[BSIZE];75 struct dinode din;767778 static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");7980 if(argc < 2){81 fprintf(stderr, "Usage: mkfs fs.img files...\n");82 exit(1);83 }8485 assert((BSIZE % sizeof(struct dinode)) == 0);86 assert((BSIZE % sizeof(struct dirent)) == 0);8788 fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);89 if(fsfd < 0)90 die(argv[1]);9192 // 1 fs block = 1 disk sector93 nmeta = 2 + nlog + ninodeblocks + nbitmap;94 nblocks = FSSIZE - nmeta;9596 sb.magic = FSMAGIC;97 sb.size = xint(FSSIZE);98 sb.nblocks = xint(nblocks);99 sb.ninodes = xint(NINODES);100 sb.nlog = xint(nlog);101 sb.logstart = xint(2);102 sb.inodestart = xint(2+nlog);103 sb.bmapstart = xint(2+nlog+ninodeblocks);104105 printf("nmeta %d (boot, super, log blocks %u, inode blocks %u, bitmap blocks %u) blocks %d total %d\n",106 nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);107108 freeblock = nmeta; // the first free block that we can allocate109110 for(i = 0; i < FSSIZE; i++)111 wsect(i, zeroes);112113 memset(buf, 0, sizeof(buf));114 memmove(buf, &sb, sizeof(sb));115 wsect(1, buf);116117 rootino = ialloc(T_DIR);118 assert(rootino == ROOTINO);119120 bzero(&de, sizeof(de));121 de.inum = xshort(rootino);122 strcpy(de.name, ".");123 iappend(rootino, &de, sizeof(de));124125 bzero(&de, sizeof(de));126 de.inum = xshort(rootino);127 strcpy(de.name, "..");128 iappend(rootino, &de, sizeof(de));129130 for(i = 2; i < argc; i++){131 // get rid of "user/"132 char *shortname;133 if(strncmp(argv[i], "user/", 5) == 0)134 shortname = argv[i] + 5;135 else136 shortname = argv[i];137 138 assert(index(shortname, '/') == 0);139140 if((fd = open(argv[i], 0)) < 0)141 die(argv[i]);142143 // Skip leading _ in name when writing to file system.144 // The binaries are named _rm, _cat, etc. to keep the145 // build operating system from trying to execute them146 // in place of system binaries like rm and cat.147 if(shortname[0] == '_')148 shortname += 1;149150 assert(strlen(shortname) <= DIRSIZ);151 152 inum = ialloc(T_FILE);153154 bzero(&de, sizeof(de));155 de.inum = xshort(inum);156 strncpy(de.name, shortname, DIRSIZ);157 iappend(rootino, &de, sizeof(de));158159 while((cc = read(fd, buf, sizeof(buf))) > 0)160 iappend(inum, buf, cc);161162 close(fd);163 }164165 // fix size of root inode dir166 rinode(rootino, &din);167 off = xint(din.size);168 off = ((off/BSIZE) + 1) * BSIZE;169 din.size = xint(off);170 winode(rootino, &din);171172 balloc(freeblock);173174 exit(0);175}176177void178wsect(uint sec, void *buf)179{180 if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)181 die("lseek");182 if(write(fsfd, buf, BSIZE) != BSIZE)183 die("write");184}185186void187winode(uint inum, struct dinode *ip)188{189 char buf[BSIZE];190 uint bn;191 struct dinode *dip;192193 bn = IBLOCK(inum, sb);194 rsect(bn, buf);195 dip = ((struct dinode*)buf) + (inum % IPB);196 *dip = *ip;197 wsect(bn, buf);198}199200void201rinode(uint inum, struct dinode *ip)202{203 char buf[BSIZE];204 uint bn;205 struct dinode *dip;206207 bn = IBLOCK(inum, sb);208 rsect(bn, buf);209 dip = ((struct dinode*)buf) + (inum % IPB);210 *ip = *dip;211}212213void214rsect(uint sec, void *buf)215{216 if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)217 die("lseek");218 if(read(fsfd, buf, BSIZE) != BSIZE)219 die("read");220}221222uint223ialloc(ushort type)224{225 uint inum = freeinode++;226 struct dinode din;227228 bzero(&din, sizeof(din));229 din.type = xshort(type);230 din.nlink = xshort(1);231 din.size = xint(0);232 winode(inum, &din);233 return inum;234}235236void237balloc(int used)238{239 uchar buf[BSIZE];240 int i;241242 printf("balloc: first %d blocks have been allocated\n", used);243 assert(used < BPB);244 bzero(buf, BSIZE);245 for(i = 0; i < used; i++){246 buf[i/8] = buf[i/8] | (0x1 << (i%8));247 }248 printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);249 wsect(sb.bmapstart, buf);250}251252#define min(a, b) ((a) < (b) ? (a) : (b))253254void255iappend(uint inum, void *xp, int n)256{257 char *p = (char*)xp;258 uint fbn, off, n1;259 struct dinode din;260 char buf[BSIZE];261 uint indirect[NINDIRECT];262 uint x;263264 rinode(inum, &din);265 off = xint(din.size);266 // printf("append inum %d at off %d sz %d\n", inum, off, n);267 while(n > 0){268 fbn = off / BSIZE;269 assert(fbn < MAXFILE);270 if(fbn < NDIRECT){271 if(xint(din.addrs[fbn]) == 0){272 din.addrs[fbn] = xint(freeblock++);273 }274 x = xint(din.addrs[fbn]);275 } else {276 if(xint(din.addrs[NDIRECT]) == 0){277 din.addrs[NDIRECT] = xint(freeblock++);278 }279 rsect(xint(din.addrs[NDIRECT]), (char*)indirect);280 if(indirect[fbn - NDIRECT] == 0){281 indirect[fbn - NDIRECT] = xint(freeblock++);282 wsect(xint(din.addrs[NDIRECT]), (char*)indirect);283 }284 x = xint(indirect[fbn-NDIRECT]);285 }286 n1 = min(n, (fbn + 1) * BSIZE - off);287 rsect(x, buf);288 bcopy(p, buf + off - (fbn * BSIZE), n1);289 wsect(x, buf);290 n -= n1;291 off += n1;292 p += n1;293 }294 din.size = xint(off);295 winode(inum, &din);296}297298void299die(const char *s)300{301 perror(s);302 exit(1);303}304