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