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