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