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