xref: /xv6-public/mkfs.c (revision 7894fcd2)
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
xshort(ushort x)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
xint(uint x)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
main(int argc,char * argv[])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
wsect(uint sec,void * buf)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
winode(uint inum,struct dinode * ip)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
rinode(uint inum,struct dinode * ip)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
rsect(uint sec,void * buf)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
ialloc(ushort type)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
balloc(int used)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
iappend(uint inum,void * xp,int n)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