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