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