287 lines
5.4 KiB
C
287 lines
5.4 KiB
C
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <assert.h>
|
|
#include "types.h"
|
|
#include "param.h"
|
|
#include "fs.h"
|
|
|
|
int nblocks = 1008;
|
|
int ninodes = 100;
|
|
int size = 1024;
|
|
|
|
int fsfd;
|
|
struct superblock sb;
|
|
char zeroes[512];
|
|
uint freeblock;
|
|
uint usedblocks;
|
|
uint bitblocks;
|
|
uint freeinode = 1;
|
|
|
|
void balloc(int);
|
|
void wsect(uint, void*);
|
|
void winode(uint, struct dinode*);
|
|
void rinode(uint inum, struct dinode *ip);
|
|
void rsect(uint sec, void *buf);
|
|
uint ialloc(ushort type);
|
|
void iappend(uint inum, void *p, int n);
|
|
|
|
// convert to intel byte order
|
|
ushort
|
|
xshort(ushort x)
|
|
{
|
|
ushort y;
|
|
uchar *a = (uchar*) &y;
|
|
a[0] = x;
|
|
a[1] = x >> 8;
|
|
return y;
|
|
}
|
|
|
|
uint
|
|
xint(uint x)
|
|
{
|
|
uint y;
|
|
uchar *a = (uchar*) &y;
|
|
a[0] = x;
|
|
a[1] = x >> 8;
|
|
a[2] = x >> 16;
|
|
a[3] = x >> 24;
|
|
return y;
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i, cc, fd;
|
|
uint bn, rootino, inum, off;
|
|
struct dirent de;
|
|
char buf[512];
|
|
struct dinode din;
|
|
|
|
if(argc < 2){
|
|
fprintf(stderr, "Usage: mkfs fs.img files...\n");
|
|
exit(1);
|
|
}
|
|
|
|
assert((512 % sizeof(struct dinode)) == 0);
|
|
assert((512 % sizeof(struct dirent)) == 0);
|
|
|
|
fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
|
|
if(fsfd < 0){
|
|
perror(argv[1]);
|
|
exit(1);
|
|
}
|
|
|
|
sb.size = xint(size);
|
|
sb.nblocks = xint(nblocks); // so whole disk is size sectors
|
|
sb.ninodes = xint(ninodes);
|
|
|
|
bitblocks = size/(512*8) + 1;
|
|
usedblocks = ninodes / IPB + 3 + bitblocks;
|
|
freeblock = usedblocks;
|
|
|
|
printf("used %d (bit %d ninode %d) free %d total %d\n", usedblocks,
|
|
bitblocks, ninodes/IPB + 1, freeblock, nblocks+usedblocks);
|
|
|
|
assert(nblocks + usedblocks == size);
|
|
|
|
for(i = 0; i < nblocks + usedblocks; i++)
|
|
wsect(i, zeroes);
|
|
|
|
wsect(1, &sb);
|
|
|
|
rootino = ialloc(T_DIR);
|
|
assert(rootino == 1);
|
|
|
|
bzero(&de, sizeof(de));
|
|
de.inum = xshort(rootino);
|
|
strcpy(de.name, ".");
|
|
iappend(rootino, &de, sizeof(de));
|
|
|
|
bzero(&de, sizeof(de));
|
|
de.inum = xshort(rootino);
|
|
strcpy(de.name, "..");
|
|
iappend(rootino, &de, sizeof(de));
|
|
|
|
for(i = 2; i < argc; i++){
|
|
assert(index(argv[i], '/') == 0);
|
|
|
|
if((fd = open(argv[i], 0)) < 0){
|
|
perror(argv[i]);
|
|
exit(1);
|
|
}
|
|
|
|
// Skip leading _ in name when writing to file system.
|
|
// The binaries are named _rm, _cat, etc. to keep the
|
|
// build operating system from trying to execute them
|
|
// in place of system binaries like rm and cat.
|
|
if(argv[i][0] == '_')
|
|
++argv[i];
|
|
|
|
inum = ialloc(T_FILE);
|
|
|
|
bzero(&de, sizeof(de));
|
|
de.inum = xshort(inum);
|
|
strncpy(de.name, argv[i], DIRSIZ);
|
|
iappend(rootino, &de, sizeof(de));
|
|
|
|
while((cc = read(fd, buf, sizeof(buf))) > 0)
|
|
iappend(inum, buf, cc);
|
|
|
|
close(fd);
|
|
}
|
|
|
|
// fix size of root inode dir
|
|
rinode(rootino, &din);
|
|
off = xint(din.size);
|
|
off = ((off/BSIZE) + 1) * BSIZE;
|
|
din.size = xint(off);
|
|
winode(rootino, &din);
|
|
|
|
balloc(usedblocks);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
void
|
|
wsect(uint sec, void *buf)
|
|
{
|
|
if(lseek(fsfd, sec * 512L, 0) != sec * 512L){
|
|
perror("lseek");
|
|
exit(1);
|
|
}
|
|
if(write(fsfd, buf, 512) != 512){
|
|
perror("write");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
uint
|
|
i2b(uint inum)
|
|
{
|
|
return (inum / IPB) + 2;
|
|
}
|
|
|
|
void
|
|
winode(uint inum, struct dinode *ip)
|
|
{
|
|
char buf[512];
|
|
uint bn;
|
|
struct dinode *dip;
|
|
|
|
bn = i2b(inum);
|
|
rsect(bn, buf);
|
|
dip = ((struct dinode*) buf) + (inum % IPB);
|
|
*dip = *ip;
|
|
wsect(bn, buf);
|
|
}
|
|
|
|
void
|
|
rinode(uint inum, struct dinode *ip)
|
|
{
|
|
char buf[512];
|
|
uint bn;
|
|
struct dinode *dip;
|
|
|
|
bn = i2b(inum);
|
|
rsect(bn, buf);
|
|
dip = ((struct dinode*) buf) + (inum % IPB);
|
|
*ip = *dip;
|
|
}
|
|
|
|
void
|
|
rsect(uint sec, void *buf)
|
|
{
|
|
if(lseek(fsfd, sec * 512L, 0) != sec * 512L){
|
|
perror("lseek");
|
|
exit(1);
|
|
}
|
|
if(read(fsfd, buf, 512) != 512){
|
|
perror("read");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
uint
|
|
ialloc(ushort type)
|
|
{
|
|
uint inum = freeinode++;
|
|
struct dinode din;
|
|
|
|
bzero(&din, sizeof(din));
|
|
din.type = xshort(type);
|
|
din.nlink = xshort(1);
|
|
din.size = xint(0);
|
|
winode(inum, &din);
|
|
return inum;
|
|
}
|
|
|
|
void
|
|
balloc(int used)
|
|
{
|
|
uchar buf[512];
|
|
int i;
|
|
|
|
printf("balloc: first %d blocks have been allocated\n", used);
|
|
assert(used < 512);
|
|
bzero(buf, 512);
|
|
for(i = 0; i < used; i++) {
|
|
buf[i/8] = buf[i/8] | (0x1 << (i%8));
|
|
}
|
|
printf("balloc: write bitmap block at sector %d\n", ninodes/IPB + 3);
|
|
wsect(ninodes / IPB + 3, buf);
|
|
}
|
|
|
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
void
|
|
iappend(uint inum, void *xp, int n)
|
|
{
|
|
char *p = (char*) xp;
|
|
uint fbn, off, n1;
|
|
struct dinode din;
|
|
char buf[512];
|
|
uint indirect[NINDIRECT];
|
|
uint x;
|
|
|
|
rinode(inum, &din);
|
|
|
|
off = xint(din.size);
|
|
while(n > 0){
|
|
fbn = off / 512;
|
|
assert(fbn < MAXFILE);
|
|
if(fbn < NDIRECT) {
|
|
if(xint(din.addrs[fbn]) == 0) {
|
|
din.addrs[fbn] = xint(freeblock++);
|
|
usedblocks++;
|
|
}
|
|
x = xint(din.addrs[fbn]);
|
|
} else {
|
|
if(xint(din.addrs[INDIRECT]) == 0) {
|
|
// printf("allocate indirect block\n");
|
|
din.addrs[INDIRECT] = xint(freeblock++);
|
|
usedblocks++;
|
|
}
|
|
// printf("read indirect block\n");
|
|
rsect(xint(din.addrs[INDIRECT]), (char*) indirect);
|
|
if(indirect[fbn - NDIRECT] == 0) {
|
|
indirect[fbn - NDIRECT] = xint(freeblock++);
|
|
usedblocks++;
|
|
wsect(xint(din.addrs[INDIRECT]), (char*) indirect);
|
|
}
|
|
x = xint(indirect[fbn-NDIRECT]);
|
|
}
|
|
n1 = min(n, (fbn + 1) * 512 - off);
|
|
rsect(x, buf);
|
|
bcopy(p, buf + off - (fbn * 512), n1);
|
|
wsect(x, buf);
|
|
n -= n1;
|
|
off += n1;
|
|
p += n1;
|
|
}
|
|
din.size = xint(off);
|
|
winode(inum, &din);
|
|
}
|