xref: /xv6-public/mkfs.c (revision 895af77f)
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