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