1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <fcntl.h> 6 #include <assert.h> 7 8 #define stat xv6_stat // avoid clash with host struct stat 9 #include "types.h" 10 #include "fs.h" 11 #include "stat.h" 12 #include "param.h" 13 14 #define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0) 15 16 #define NINODES 200 17 18 // Disk layout: 19 // [ boot block | sb block | inode blocks | bit map | data blocks | log ] 20 21 int nbitmap = FSSIZE/(BSIZE*8) + 1; 22 int ninodeblocks = NINODES / IPB + 1; 23 int nlog = LOGSIZE; 24 int nmeta; // Number of meta blocks (inode, bitmap, and 2 extra) 25 int nblocks; // Number of data blocks 26 27 int fsfd; 28 struct superblock sb; 29 char zeroes[BSIZE]; 30 uint freeinode = 1; 31 uint freeblock; 32 33 34 void balloc(int); 35 void wsect(uint, void*); 36 void winode(uint, struct dinode*); 37 void rinode(uint inum, struct dinode *ip); 38 void rsect(uint sec, void *buf); 39 uint ialloc(ushort type); 40 void iappend(uint inum, void *p, int n); 41 42 // convert to intel byte order 43 ushort 44 xshort(ushort x) 45 { 46 ushort y; 47 uchar *a = (uchar*)&y; 48 a[0] = x; 49 a[1] = x >> 8; 50 return y; 51 } 52 53 uint 54 xint(uint x) 55 { 56 uint y; 57 uchar *a = (uchar*)&y; 58 a[0] = x; 59 a[1] = x >> 8; 60 a[2] = x >> 16; 61 a[3] = x >> 24; 62 return y; 63 } 64 65 int 66 main(int argc, char *argv[]) 67 { 68 int i, cc, fd; 69 uint rootino, inum, off; 70 struct dirent de; 71 char buf[BSIZE]; 72 struct dinode din; 73 74 75 static_assert(sizeof(int) == 4, "Integers must be 4 bytes!"); 76 77 if(argc < 2){ 78 fprintf(stderr, "Usage: mkfs fs.img files...\n"); 79 exit(1); 80 } 81 82 assert((BSIZE % sizeof(struct dinode)) == 0); 83 assert((BSIZE % sizeof(struct dirent)) == 0); 84 85 fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); 86 if(fsfd < 0){ 87 perror(argv[1]); 88 exit(1); 89 } 90 91 nmeta = 2 + ninodeblocks + nbitmap; 92 nblocks = FSSIZE - nlog - nmeta; 93 94 sb.size = xint(FSSIZE); 95 sb.nblocks = xint(nblocks); // so whole disk is size sectors 96 sb.ninodes = xint(NINODES); 97 sb.nlog = xint(nlog); 98 99 printf("nmeta %d (boot, super, inode blocks %u, bitmap blocks %u) blocks %d log %u total %d\n", nmeta, ninodeblocks, nbitmap, nblocks, nlog, FSSIZE); 100 101 freeblock = nmeta; // the first free block that we can allocate 102 103 for(i = 0; i < FSSIZE; i++) 104 wsect(i, zeroes); 105 106 memset(buf, 0, sizeof(buf)); 107 memmove(buf, &sb, sizeof(sb)); 108 wsect(1, buf); 109 110 rootino = ialloc(T_DIR); 111 assert(rootino == ROOTINO); 112 113 bzero(&de, sizeof(de)); 114 de.inum = xshort(rootino); 115 strcpy(de.name, "."); 116 iappend(rootino, &de, sizeof(de)); 117 118 bzero(&de, sizeof(de)); 119 de.inum = xshort(rootino); 120 strcpy(de.name, ".."); 121 iappend(rootino, &de, sizeof(de)); 122 123 for(i = 2; i < argc; i++){ 124 assert(index(argv[i], '/') == 0); 125 126 if((fd = open(argv[i], 0)) < 0){ 127 perror(argv[i]); 128 exit(1); 129 } 130 131 // Skip leading _ in name when writing to file system. 132 // The binaries are named _rm, _cat, etc. to keep the 133 // build operating system from trying to execute them 134 // in place of system binaries like rm and cat. 135 if(argv[i][0] == '_') 136 ++argv[i]; 137 138 inum = ialloc(T_FILE); 139 140 bzero(&de, sizeof(de)); 141 de.inum = xshort(inum); 142 strncpy(de.name, argv[i], DIRSIZ); 143 iappend(rootino, &de, sizeof(de)); 144 145 while((cc = read(fd, buf, sizeof(buf))) > 0) 146 iappend(inum, buf, cc); 147 148 close(fd); 149 } 150 151 // fix size of root inode dir 152 rinode(rootino, &din); 153 off = xint(din.size); 154 off = ((off/BSIZE) + 1) * BSIZE; 155 din.size = xint(off); 156 winode(rootino, &din); 157 158 balloc(freeblock); 159 160 exit(0); 161 } 162 163 void 164 wsect(uint sec, void *buf) 165 { 166 if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){ 167 perror("lseek"); 168 exit(1); 169 } 170 if(write(fsfd, buf, BSIZE) != BSIZE){ 171 perror("write"); 172 exit(1); 173 } 174 } 175 176 void 177 winode(uint inum, struct dinode *ip) 178 { 179 char buf[BSIZE]; 180 uint bn; 181 struct dinode *dip; 182 183 bn = IBLOCK(inum); 184 rsect(bn, buf); 185 dip = ((struct dinode*)buf) + (inum % IPB); 186 *dip = *ip; 187 wsect(bn, buf); 188 } 189 190 void 191 rinode(uint inum, struct dinode *ip) 192 { 193 char buf[BSIZE]; 194 uint bn; 195 struct dinode *dip; 196 197 bn = IBLOCK(inum); 198 rsect(bn, buf); 199 dip = ((struct dinode*)buf) + (inum % IPB); 200 *ip = *dip; 201 } 202 203 void 204 rsect(uint sec, void *buf) 205 { 206 if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){ 207 perror("lseek"); 208 exit(1); 209 } 210 if(read(fsfd, buf, BSIZE) != BSIZE){ 211 perror("read"); 212 exit(1); 213 } 214 } 215 216 uint 217 ialloc(ushort type) 218 { 219 uint inum = freeinode++; 220 struct dinode din; 221 222 bzero(&din, sizeof(din)); 223 din.type = xshort(type); 224 din.nlink = xshort(1); 225 din.size = xint(0); 226 winode(inum, &din); 227 return inum; 228 } 229 230 void 231 balloc(int used) 232 { 233 uchar buf[BSIZE]; 234 int i; 235 236 printf("balloc: first %d blocks have been allocated\n", used); 237 assert(used < BSIZE*8); 238 bzero(buf, BSIZE); 239 for(i = 0; i < used; i++){ 240 buf[i/8] = buf[i/8] | (0x1 << (i%8)); 241 } 242 printf("balloc: write bitmap block at sector %d\n", ninodeblocks+2); 243 wsect(ninodeblocks+2, buf); 244 } 245 246 #define min(a, b) ((a) < (b) ? (a) : (b)) 247 248 void 249 iappend(uint inum, void *xp, int n) 250 { 251 char *p = (char*)xp; 252 uint fbn, off, n1; 253 struct dinode din; 254 char buf[BSIZE]; 255 uint indirect[NINDIRECT]; 256 uint x; 257 258 rinode(inum, &din); 259 260 off = xint(din.size); 261 while(n > 0){ 262 fbn = off / BSIZE; 263 assert(fbn < MAXFILE); 264 if(fbn < NDIRECT){ 265 if(xint(din.addrs[fbn]) == 0){ 266 din.addrs[fbn] = xint(freeblock++); 267 } 268 x = xint(din.addrs[fbn]); 269 } else { 270 if(xint(din.addrs[NDIRECT]) == 0){ 271 // printf("allocate indirect block\n"); 272 din.addrs[NDIRECT] = xint(freeblock++); 273 } 274 // printf("read indirect block\n"); 275 rsect(xint(din.addrs[NDIRECT]), (char*)indirect); 276 if(indirect[fbn - NDIRECT] == 0){ 277 indirect[fbn - NDIRECT] = xint(freeblock++); 278 wsect(xint(din.addrs[NDIRECT]), (char*)indirect); 279 } 280 x = xint(indirect[fbn-NDIRECT]); 281 } 282 n1 = min(n, (fbn + 1) * BSIZE - off); 283 rsect(x, buf); 284 bcopy(p, buf + off - (fbn * BSIZE), n1); 285 wsect(x, buf); 286 n -= n1; 287 off += n1; 288 p += n1; 289 } 290 din.size = xint(off); 291 winode(inum, &din); 292 } 293