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 | log | inode blocks | free bit map | data blocks ] 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 (boot, sb, nlog, inode, bitmap) 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 // 1 fs block = 1 disk sector 92 nmeta = 2 + nlog + ninodeblocks + nbitmap; 93 nblocks = FSSIZE - nmeta; 94 95 sb.size = xint(FSSIZE); 96 sb.nblocks = xint(nblocks); 97 sb.ninodes = xint(NINODES); 98 sb.nlog = xint(nlog); 99 sb.logstart = xint(2); 100 sb.inodestart = xint(2+nlog); 101 sb.bmapstart = xint(2+nlog+ninodeblocks); 102 103 printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n", 104 nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE); 105 106 freeblock = nmeta; // the first free block that we can allocate 107 108 for(i = 0; i < FSSIZE; i++) 109 wsect(i, zeroes); 110 111 memset(buf, 0, sizeof(buf)); 112 memmove(buf, &sb, sizeof(sb)); 113 wsect(1, buf); 114 115 rootino = ialloc(T_DIR); 116 assert(rootino == ROOTINO); 117 118 bzero(&de, sizeof(de)); 119 de.inum = xshort(rootino); 120 strcpy(de.name, "."); 121 iappend(rootino, &de, sizeof(de)); 122 123 bzero(&de, sizeof(de)); 124 de.inum = xshort(rootino); 125 strcpy(de.name, ".."); 126 iappend(rootino, &de, sizeof(de)); 127 128 for(i = 2; i < argc; i++){ 129 assert(index(argv[i], '/') == 0); 130 131 if((fd = open(argv[i], 0)) < 0){ 132 perror(argv[i]); 133 exit(1); 134 } 135 136 // Skip leading _ in name when writing to file system. 137 // The binaries are named _rm, _cat, etc. to keep the 138 // build operating system from trying to execute them 139 // in place of system binaries like rm and cat. 140 if(argv[i][0] == '_') 141 ++argv[i]; 142 143 inum = ialloc(T_FILE); 144 145 bzero(&de, sizeof(de)); 146 de.inum = xshort(inum); 147 strncpy(de.name, argv[i], DIRSIZ); 148 iappend(rootino, &de, sizeof(de)); 149 150 while((cc = read(fd, buf, sizeof(buf))) > 0) 151 iappend(inum, buf, cc); 152 153 close(fd); 154 } 155 156 // fix size of root inode dir 157 rinode(rootino, &din); 158 off = xint(din.size); 159 off = ((off/BSIZE) + 1) * BSIZE; 160 din.size = xint(off); 161 winode(rootino, &din); 162 163 balloc(freeblock); 164 165 exit(0); 166 } 167 168 void 169 wsect(uint sec, void *buf) 170 { 171 if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){ 172 perror("lseek"); 173 exit(1); 174 } 175 if(write(fsfd, buf, BSIZE) != BSIZE){ 176 perror("write"); 177 exit(1); 178 } 179 } 180 181 void 182 winode(uint inum, struct dinode *ip) 183 { 184 char buf[BSIZE]; 185 uint bn; 186 struct dinode *dip; 187 188 bn = IBLOCK(inum, sb); 189 rsect(bn, buf); 190 dip = ((struct dinode*)buf) + (inum % IPB); 191 *dip = *ip; 192 wsect(bn, buf); 193 } 194 195 void 196 rinode(uint inum, struct dinode *ip) 197 { 198 char buf[BSIZE]; 199 uint bn; 200 struct dinode *dip; 201 202 bn = IBLOCK(inum, sb); 203 rsect(bn, buf); 204 dip = ((struct dinode*)buf) + (inum % IPB); 205 *ip = *dip; 206 } 207 208 void 209 rsect(uint sec, void *buf) 210 { 211 if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){ 212 perror("lseek"); 213 exit(1); 214 } 215 if(read(fsfd, buf, BSIZE) != BSIZE){ 216 perror("read"); 217 exit(1); 218 } 219 } 220 221 uint 222 ialloc(ushort type) 223 { 224 uint inum = freeinode++; 225 struct dinode din; 226 227 bzero(&din, sizeof(din)); 228 din.type = xshort(type); 229 din.nlink = xshort(1); 230 din.size = xint(0); 231 winode(inum, &din); 232 return inum; 233 } 234 235 void 236 balloc(int used) 237 { 238 uchar buf[BSIZE]; 239 int i; 240 241 printf("balloc: first %d blocks have been allocated\n", used); 242 assert(used < BSIZE*8); 243 bzero(buf, BSIZE); 244 for(i = 0; i < used; i++){ 245 buf[i/8] = buf[i/8] | (0x1 << (i%8)); 246 } 247 printf("balloc: write bitmap block at sector %d\n", sb.bmapstart); 248 wsect(sb.bmapstart, buf); 249 } 250 251 #define min(a, b) ((a) < (b) ? (a) : (b)) 252 253 void 254 iappend(uint inum, void *xp, int n) 255 { 256 char *p = (char*)xp; 257 uint fbn, off, n1; 258 struct dinode din; 259 char buf[BSIZE]; 260 uint indirect[NINDIRECT]; 261 uint x; 262 263 rinode(inum, &din); 264 off = xint(din.size); 265 // printf("append inum %d at off %d sz %d\n", inum, off, n); 266 while(n > 0){ 267 fbn = off / BSIZE; 268 assert(fbn < MAXFILE); 269 if(fbn < NDIRECT){ 270 if(xint(din.addrs[fbn]) == 0){ 271 din.addrs[fbn] = xint(freeblock++); 272 } 273 x = xint(din.addrs[fbn]); 274 } else { 275 if(xint(din.addrs[NDIRECT]) == 0){ 276 din.addrs[NDIRECT] = xint(freeblock++); 277 } 278 rsect(xint(din.addrs[NDIRECT]), (char*)indirect); 279 if(indirect[fbn - NDIRECT] == 0){ 280 indirect[fbn - NDIRECT] = xint(freeblock++); 281 wsect(xint(din.addrs[NDIRECT]), (char*)indirect); 282 } 283 x = xint(indirect[fbn-NDIRECT]); 284 } 285 n1 = min(n, (fbn + 1) * BSIZE - off); 286 rsect(x, buf); 287 bcopy(p, buf + off - (fbn * BSIZE), n1); 288 wsect(x, buf); 289 n -= n1; 290 off += n1; 291 p += n1; 292 } 293 din.size = xint(off); 294 winode(inum, &din); 295 } 296