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