OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /eco32/trunk
    from Rev 16 to Rev 17
    Reverse comparison

Rev 16 → Rev 17

/disk/tools/Makefile.run
0,0 → 1,29
#
# Makefile to build a bootable disk, and either start the
# ECO32 simulator with a ROM monitor (goal: run an OS within
# the simulator) or start the serial line disk server (goal:
# run an OS on an FPGA board).
#
 
BUILD = ..
 
all: disk.img
 
run-sim: disk.img
$(BUILD)/bin/sim -i -t 1 \
-r $(BUILD)/monitor/monitor.bin \
-d disk.img -o run.log
 
run-server: disk.img
$(BUILD)/bin/diskserv disk.img
 
disk.img:
$(BUILD)/bin/mkdisk disk.img 100M
$(BUILD)/bin/mkpart disk.img disk.part
$(MAKE) -C fs-EOS32 all
$(MAKE) -C fs-NetBSD all
 
clean:
$(MAKE) -C fs-EOS32 clean
$(MAKE) -C fs-NetBSD clean
rm -f *~ disk.img run.log
/disk/tools/fs-EOS32/mkfs/mkfs.c
0,0 → 1,1153
/*
* mkfs.c -- make an EOS32 file system
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
 
 
/**************************************************************/
 
 
#define SSIZE 512 /* disk sector size in bytes */
#define BSIZE 4096 /* disk block size in bytes */
#define SPB (BSIZE / SSIZE) /* sectors per block */
#define AFS (3 * BSIZE / 2) /* average file size */
 
#define NICINOD 500 /* number of inodes in superblock */
#define NICFREE 500 /* number of free blocks in superblock */
#define NADDR 8 /* number of block addresses in inode */
#define NDADDR 6 /* number of direct block addresses */
#define SINGLE_INDIR (NDADDR + 0) /* index of single indirect block */
#define DOUBLE_INDIR (NDADDR + 1) /* index of double indirect block */
#define DIRSIZ 60 /* max length of a path name component */
 
#define NIPB (BSIZE / sizeof(Dinode))
#define NDIRENT (BSIZE / sizeof(Dirent))
#define NINDIR (BSIZE / sizeof(EOS32_daddr_t))
 
#define SUPER_MAGIC 0x44FCB67D
 
#define IFMT 070000 /* type of file */
#define IFREG 040000 /* regular file */
#define IFDIR 030000 /* directory */
#define IFCHR 020000 /* character special */
#define IFBLK 010000 /* block special */
#define IFFREE 000000 /* reserved (indicates free inode) */
#define ISUID 004000 /* set user id on execution */
#define ISGID 002000 /* set group id on execution */
#define ISVTX 001000 /* save swapped text even after use */
#define IUREAD 000400 /* user's read permission */
#define IUWRITE 000200 /* user's write permission */
#define IUEXEC 000100 /* user's execute permission */
#define IGREAD 000040 /* group's read permission */
#define IGWRITE 000020 /* group's write permission */
#define IGEXEC 000010 /* group's execute permission */
#define IOREAD 000004 /* other's read permission */
#define IOWRITE 000002 /* other's write permission */
#define IOEXEC 000001 /* other's execute permission */
 
/*
* The following two macros convert an inode number to the disk
* block containing the inode and an inode number within the block.
*/
#define itod(i) (2 + (i) / NIPB)
#define itoo(i) ((i) % NIPB)
 
#define TYPE_COPY 0
#define TYPE_INODE 1
#define TYPE_FREE 2
#define TYPE_SUPER 3
#define TYPE_INDIRECT 4
#define TYPE_DIRECTORY 5
 
 
/**************************************************************/
 
 
/* EOS32 types */
 
typedef unsigned long EOS32_ino_t;
typedef unsigned long EOS32_daddr_t;
typedef unsigned long EOS32_off_t;
typedef long EOS32_time_t;
 
 
/* super block */
 
typedef struct {
unsigned int s_magic; /* must be SUPER_MAGIC */
EOS32_daddr_t s_fsize; /* size of file system in blocks */
EOS32_daddr_t s_isize; /* size of inode list in blocks */
EOS32_daddr_t s_freeblks; /* number of free blocks */
EOS32_ino_t s_freeinos; /* number of free inodes */
unsigned int s_ninode; /* number of inodes in s_inode */
EOS32_ino_t s_inode[NICINOD]; /* free inode list */
unsigned int s_nfree; /* number of addresses in s_free */
EOS32_daddr_t s_free[NICFREE]; /* free block list */
EOS32_time_t s_time; /* last super block update */
char s_flock; /* lock for free list manipulation */
char s_ilock; /* lock for i-list manipulation */
char s_fmod; /* super block modified flag */
char s_ronly; /* mounted read-only flag */
char s_pad[BSIZE - 4036]; /* pad to block size */
} Filsys;
 
 
/* inode on disk */
 
typedef struct {
unsigned int di_mode; /* type and mode of file */
unsigned int di_nlink; /* number of links to file */
unsigned int di_uid; /* owner's user id */
unsigned int di_gid; /* owner's group id */
EOS32_time_t di_ctime; /* time created */
EOS32_time_t di_mtime; /* time last modified */
EOS32_time_t di_atime; /* time last accessed */
EOS32_off_t di_size; /* number of bytes in file */
EOS32_daddr_t di_addr[NADDR]; /* block addresses */
} Dinode;
 
 
/* inode in memory */
 
typedef struct {
EOS32_ino_t i_number; /* inode number */
unsigned int i_mode; /* type and mode of file */
unsigned int i_nlink; /* number of links to file */
unsigned int i_uid; /* owner's user id */
unsigned int i_gid; /* owner's group id */
EOS32_off_t i_size; /* number of bytes in file */
EOS32_daddr_t i_addr[NADDR]; /* block addresses */
} Inode;
 
 
/* directory entry */
 
typedef struct {
EOS32_ino_t d_ino; /* directory inode */
char d_name[DIRSIZ]; /* directory name */
} Dirent;
 
 
/* free block */
 
typedef struct {
unsigned int df_nfree; /* number of valid block addresses */
EOS32_daddr_t df_free[NICFREE]; /* addresses of free blocks */
char df_pad[BSIZE - 2004]; /* pad to block size */
} Fblk;
 
 
/**************************************************************/
 
 
time_t now; /* timestamp used throughout the file system */
FILE *fs; /* the file which holds the disk image */
Filsys filsys; /* the file system's super block */
EOS32_ino_t lastIno; /* last inode allocated */
 
 
/**************************************************************/
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
printf("Error: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
exit(1);
}
 
 
/**************************************************************/
 
 
unsigned int read4FromEco(unsigned char *p) {
return (unsigned int) p[0] << 24 |
(unsigned int) p[1] << 16 |
(unsigned int) p[2] << 8 |
(unsigned int) p[3] << 0;
}
 
 
void write4ToEco(unsigned char *p, unsigned int data) {
p[0] = data >> 24;
p[1] = data >> 16;
p[2] = data >> 8;
p[3] = data >> 0;
}
 
 
void conv4FromEcoToX86(unsigned char *p) {
unsigned int data;
 
data = read4FromEco(p);
* (unsigned int *) p = data;
}
 
 
void conv4FromX86ToEco(unsigned char *p) {
unsigned int data;
 
data = * (unsigned int *) p;
write4ToEco(p, data);
}
 
 
/**************************************************************/
 
 
void superFromEcoToX86(unsigned char *p) {
int i;
 
/* magic */
conv4FromEcoToX86(p);
p += 4;
/* fsize */
conv4FromEcoToX86(p);
p += 4;
/* isize */
conv4FromEcoToX86(p);
p += 4;
/* freeblks */
conv4FromEcoToX86(p);
p += 4;
/* freeinos */
conv4FromEcoToX86(p);
p += 4;
/* ninode */
conv4FromEcoToX86(p);
p += 4;
/* inode */
for (i = 0; i < NICINOD; i++) {
conv4FromEcoToX86(p);
p += 4;
}
/* nfree */
conv4FromEcoToX86(p);
p += 4;
/* free */
for (i = 0; i < NICFREE; i++) {
conv4FromEcoToX86(p);
p += 4;
}
/* time */
conv4FromEcoToX86(p);
p += 4;
/* flock */
p += 1;
/* ilock */
p += 1;
/* fmod */
p += 1;
/* ronly */
p += 1;
}
 
 
void superFromX86ToEco(unsigned char *p) {
int i;
 
/* magic */
conv4FromX86ToEco(p);
p += 4;
/* fsize */
conv4FromX86ToEco(p);
p += 4;
/* isize */
conv4FromX86ToEco(p);
p += 4;
/* freeblks */
conv4FromX86ToEco(p);
p += 4;
/* freeinos */
conv4FromX86ToEco(p);
p += 4;
/* ninode */
conv4FromX86ToEco(p);
p += 4;
/* inode */
for (i = 0; i < NICINOD; i++) {
conv4FromX86ToEco(p);
p += 4;
}
/* nfree */
conv4FromX86ToEco(p);
p += 4;
/* free */
for (i = 0; i < NICFREE; i++) {
conv4FromX86ToEco(p);
p += 4;
}
/* time */
conv4FromX86ToEco(p);
p += 4;
/* flock */
p += 1;
/* ilock */
p += 1;
/* fmod */
p += 1;
/* ronly */
p += 1;
}
 
 
void inodeFromEcoToX86(unsigned char *p) {
int i, j;
 
for (i = 0; i < NIPB; i++) {
/* mode */
conv4FromEcoToX86(p);
p += 4;
/* nlink */
conv4FromEcoToX86(p);
p += 4;
/* uid */
conv4FromEcoToX86(p);
p += 4;
/* gid */
conv4FromEcoToX86(p);
p += 4;
/* ctime */
conv4FromEcoToX86(p);
p += 4;
/* mtime */
conv4FromEcoToX86(p);
p += 4;
/* atime */
conv4FromEcoToX86(p);
p += 4;
/* size */
conv4FromEcoToX86(p);
p += 4;
/* addr */
for (j = 0; j < NADDR; j++) {
conv4FromEcoToX86(p);
p += 4;
}
}
}
 
 
void inodeFromX86ToEco(unsigned char *p) {
int i, j;
 
for (i = 0; i < NIPB; i++) {
/* mode */
conv4FromX86ToEco(p);
p += 4;
/* nlink */
conv4FromX86ToEco(p);
p += 4;
/* uid */
conv4FromX86ToEco(p);
p += 4;
/* gid */
conv4FromX86ToEco(p);
p += 4;
/* ctime */
conv4FromX86ToEco(p);
p += 4;
/* mtime */
conv4FromX86ToEco(p);
p += 4;
/* atime */
conv4FromX86ToEco(p);
p += 4;
/* size */
conv4FromX86ToEco(p);
p += 4;
/* addr */
for (j = 0; j < NADDR; j++) {
conv4FromX86ToEco(p);
p += 4;
}
}
}
 
 
void freeFromEcoToX86(unsigned char *p) {
int i;
 
/* nfree */
conv4FromEcoToX86(p);
p += 4;
/* free */
for (i = 0; i < NICFREE; i++) {
conv4FromEcoToX86(p);
p += 4;
}
}
 
 
void freeFromX86ToEco(unsigned char *p) {
int i;
 
/* nfree */
conv4FromX86ToEco(p);
p += 4;
/* free */
for (i = 0; i < NICFREE; i++) {
conv4FromX86ToEco(p);
p += 4;
}
}
 
 
void indirectFromEcoToX86(unsigned char *p) {
int i;
 
for (i = 0; i < NINDIR; i++) {
conv4FromEcoToX86(p);
p += 4;
}
}
 
 
void indirectFromX86ToEco(unsigned char *p) {
int i;
 
for (i = 0; i < NINDIR; i++) {
conv4FromX86ToEco(p);
p += 4;
}
}
 
 
void directoryFromEcoToX86(unsigned char *p) {
int i;
 
for (i = 0; i < NDIRENT; i++) {
conv4FromEcoToX86(p);
p += 4;
p += DIRSIZ;
}
}
 
 
void directoryFromX86ToEco(unsigned char *p) {
int i;
 
for (i = 0; i < NDIRENT; i++) {
conv4FromX86ToEco(p);
p += 4;
p += DIRSIZ;
}
}
 
 
/**************************************************************/
 
 
unsigned long fsStart; /* file system start sector */
 
 
void rdfs(EOS32_daddr_t bno, unsigned char *bf, int blkType) {
int n;
 
fseek(fs, fsStart * SSIZE + bno * BSIZE, SEEK_SET);
n = fread(bf, 1, BSIZE, fs);
if (n != BSIZE) {
printf("read error: %ld\n", bno);
exit(1);
}
switch (blkType) {
case TYPE_COPY:
/* nothing to do here */
break;
case TYPE_INODE:
inodeFromEcoToX86(bf);
break;
case TYPE_FREE:
freeFromEcoToX86(bf);
break;
case TYPE_SUPER:
superFromEcoToX86(bf);
break;
case TYPE_INDIRECT:
indirectFromEcoToX86(bf);
break;
case TYPE_DIRECTORY:
directoryFromEcoToX86(bf);
break;
default:
error("illegal block type %d in rdfs()", blkType);
break;
}
}
 
 
void wtfs(EOS32_daddr_t bno, unsigned char *bf, int blkType) {
int n;
 
switch (blkType) {
case TYPE_COPY:
/* nothing to do here */
break;
case TYPE_INODE:
inodeFromX86ToEco(bf);
break;
case TYPE_FREE:
freeFromX86ToEco(bf);
break;
case TYPE_SUPER:
superFromX86ToEco(bf);
break;
case TYPE_INDIRECT:
indirectFromX86ToEco(bf);
break;
case TYPE_DIRECTORY:
directoryFromX86ToEco(bf);
break;
default:
error("illegal block type %d in wtfs()", blkType);
break;
}
fseek(fs, fsStart * SSIZE + bno * BSIZE, SEEK_SET);
n = fwrite(bf, 1, BSIZE, fs);
if(n != BSIZE) {
printf("write error: %ld\n", bno);
exit(1);
}
switch (blkType) {
case TYPE_COPY:
/* nothing to do here */
break;
case TYPE_INODE:
inodeFromEcoToX86(bf);
break;
case TYPE_FREE:
freeFromEcoToX86(bf);
break;
case TYPE_SUPER:
superFromEcoToX86(bf);
break;
case TYPE_INDIRECT:
indirectFromEcoToX86(bf);
break;
case TYPE_DIRECTORY:
directoryFromEcoToX86(bf);
break;
default:
error("illegal block type %d in wtfs()", blkType);
break;
}
}
 
 
/**************************************************************/
 
 
char *charp;
FILE *fin;
char string[100];
 
 
char getChar(void) {
int c;
 
if (charp != NULL) {
/* take character from string */
c = *charp;
if (c != 0) {
charp++;
}
} else {
/* take character from prototype file */
c = getc(fin);
if (c == EOF) {
c = 0;
}
}
return c;
}
 
 
void getStr(void) {
char c;
int i;
 
while (1) {
c = getChar();
if (c == ' ' || c == '\t' || c == '\n') {
continue;
}
if (c == '\0') {
error("unexpected EOF in prototype file");
}
if (c == '#') {
do {
c = getChar();
if (c == '\0') {
error("unexpected EOF in prototype file");
}
} while (c != '\n');
continue;
}
break;
}
i = 0;
do {
string[i++] = c;
c = getChar();
} while (c != ' ' &&
c != '\t' &&
c != '\n' &&
c != '\0');
string[i] = '\0';
}
 
 
void badMode(char c) {
error("%c/%s: bad mode", c, string);
}
 
 
int getMode(char c, char *s, int m0, int m1, int m2, int m3) {
if (s[0] == 0) badMode(c);
if (c == s[0]) return m0;
if (s[1] == 0) badMode(c);
if (c == s[1]) return m1;
if (s[2] == 0) badMode(c);
if (c == s[2]) return m2;
if (s[3] == 0) badMode(c);
if (c == s[3]) return m3;
badMode(c);
/* never reached */
return 0;
}
 
 
long getNum(void) {
int i, c;
long n;
 
getStr();
n = 0;
i = 0;
for (i = 0; (c = string[i]) != '\0'; i++) {
if (c < '0' || c > '9') {
error("%s: bad number", string);
}
n = n * 10 + (c - '0');
}
return n;
}
 
 
/**************************************************************/
 
/* data block handling */
 
 
EOS32_daddr_t allocBlock(void) {
EOS32_daddr_t bno;
Fblk fbuf;
int i;
 
if (filsys.s_nfree <= 0) {
error("this should never happen (filsys.s_nfree <= 0)");
}
bno = filsys.s_free[--filsys.s_nfree];
if (bno == 0) {
error("out of free disk blocks");
}
if (filsys.s_nfree == 0) {
rdfs(bno, (unsigned char *) &fbuf, TYPE_FREE);
filsys.s_nfree = fbuf.df_nfree;
for (i = 0; i < NICFREE; i++) {
filsys.s_free[i] = fbuf.df_free[i];
}
}
filsys.s_freeblks--;
return bno;
}
 
 
void freeBlock(EOS32_daddr_t bno) {
Fblk fbuf;
int i;
 
if (filsys.s_nfree > NICFREE) {
error("this should never happen (filsys.s_nfree > NICFREE)");
}
if (filsys.s_nfree == NICFREE) {
memset(&fbuf, 0, sizeof(Fblk));
fbuf.df_nfree = NICFREE;
for (i = 0; i < NICFREE; i++) {
fbuf.df_free[i] = filsys.s_free[i];
}
wtfs(bno, (unsigned char *) &fbuf, TYPE_FREE);
filsys.s_nfree = 0;
}
filsys.s_free[filsys.s_nfree++] = bno;
if (bno != 0) {
/* note: block number 0 does not count as free block */
filsys.s_freeblks++;
}
}
 
 
void initFreeList(void) {
EOS32_daddr_t bno;
 
freeBlock(0);
for (bno = filsys.s_fsize - 1; bno >= 2 + filsys.s_isize; bno--) {
freeBlock(bno);
}
}
 
 
/**************************************************************/
 
/* inode handling */
 
 
void iput(Inode *ip) {
EOS32_daddr_t inodeBlock;
Dinode *dp;
unsigned char buf[BSIZE];
int i;
 
inodeBlock = itod(ip->i_number);
if (inodeBlock >= 2 + filsys.s_isize) {
error("too few inodes");
}
rdfs(inodeBlock, buf, TYPE_INODE);
dp = (Dinode *) buf;
dp += itoo(ip->i_number);
dp->di_mode = ip->i_mode;
dp->di_nlink = ip->i_nlink;
dp->di_uid = ip->i_uid;
dp->di_gid = ip->i_gid;
dp->di_ctime = now;
dp->di_mtime = now;
dp->di_atime = now;
dp->di_size = ip->i_size;
for (i = 0; i < NADDR; i++) {
dp->di_addr[i] = ip->i_addr[i];
}
wtfs(inodeBlock, buf, TYPE_INODE);
filsys.s_freeinos--;
}
 
 
void initInodes(void) {
int i;
EOS32_daddr_t n;
unsigned char buf[BSIZE];
Inode in;
 
/* init all inodes to free */
for (i = 0; i < BSIZE; i++) {
buf[i] = '\0';
}
for (n = 0; n < filsys.s_isize; n++) {
wtfs(2 + n, buf, TYPE_INODE);
filsys.s_freeinos += NIPB;
}
/* init inode 0 */
lastIno = 0;
in.i_number = lastIno;
in.i_mode = IFREG;
in.i_nlink = 0;
in.i_uid = 0;
in.i_gid = 0;
in.i_size = 0;
for (i = 0; i < NADDR; i++) {
in.i_addr[i] = 0;
}
iput(&in);
}
 
 
void fillFreeInodeList(EOS32_ino_t numInodes) {
int index;
EOS32_ino_t ino;
int i;
 
/* fill the free inode list starting at the upper end */
index = NICINOD;
for (ino = lastIno + 1; ino < numInodes && index > 0; ino++) {
filsys.s_inode[--index] = ino;
}
filsys.s_ninode = NICINOD - index;
/* if the list is not completely filled, shift entries down */
if (index > 0) {
for (i = 0; i < filsys.s_ninode; i++) {
filsys.s_inode[i] = filsys.s_inode[index++];
}
}
}
 
 
/**************************************************************/
 
 
void appendData(Inode *ip, int blkType, unsigned char *src, int size) {
EOS32_off_t offset;
int index1, index2;
EOS32_daddr_t bno;
unsigned char buf[BSIZE];
EOS32_daddr_t ibno;
EOS32_daddr_t iblk[NINDIR];
EOS32_daddr_t dibno;
EOS32_daddr_t diblk[NINDIR];
 
offset = ip->i_size;
if (offset < NDADDR * BSIZE) {
/* direct block */
index1 = offset / BSIZE;
offset %= BSIZE;
if (ip->i_addr[index1] == 0) {
bno = allocBlock();
ip->i_addr[index1] = bno;
memset(buf, 0, BSIZE);
} else {
bno = ip->i_addr[index1];
rdfs(bno, buf, blkType);
}
} else
if (offset < (NINDIR + NDADDR) * BSIZE) {
/* single indirect block */
offset -= NDADDR * BSIZE;
index1 = offset / BSIZE;
offset %= BSIZE;
if (ip->i_addr[SINGLE_INDIR] == 0) {
ibno = allocBlock();
ip->i_addr[SINGLE_INDIR] = ibno;
memset(iblk, 0, BSIZE);
} else {
ibno = ip->i_addr[SINGLE_INDIR];
rdfs(ibno, (unsigned char *) iblk, TYPE_INDIRECT);
}
if (iblk[index1] == 0) {
bno = allocBlock();
iblk[index1] = bno;
wtfs(ibno, (unsigned char *) iblk, TYPE_INDIRECT);
memset(buf, 0, BSIZE);
} else {
bno = iblk[index1];
rdfs(bno, buf, blkType);
}
} else {
/* double indirect block */
offset -= (NINDIR + NDADDR) * BSIZE;
index1 = offset / BSIZE;
offset %= BSIZE;
index2 = index1 / NINDIR;
index1 %= NINDIR;
if (ip->i_addr[DOUBLE_INDIR] == 0) {
dibno = allocBlock();
ip->i_addr[DOUBLE_INDIR] = dibno;
memset(diblk, 0, BSIZE);
} else {
dibno = ip->i_addr[DOUBLE_INDIR];
rdfs(dibno, (unsigned char *) diblk, TYPE_INDIRECT);
}
if (diblk[index2] == 0) {
ibno = allocBlock();
diblk[index2] = ibno;
wtfs(dibno, (unsigned char *) diblk, TYPE_INDIRECT);
memset(iblk, 0, BSIZE);
} else {
ibno = diblk[index2];
rdfs(ibno, (unsigned char *) iblk, TYPE_INDIRECT);
}
if (iblk[index1] == 0) {
bno = allocBlock();
iblk[index1] = bno;
wtfs(ibno, (unsigned char *) iblk, TYPE_INDIRECT);
memset(buf, 0, BSIZE);
} else {
bno = iblk[index1];
rdfs(bno, buf, blkType);
}
}
memcpy(buf + offset, src, size);
wtfs(bno, buf, blkType);
ip->i_size += size;
}
 
 
void makeDirEntry(Inode *dir, EOS32_ino_t ino, char *name) {
Dirent entry;
 
memset(&entry, 0, sizeof(Dirent));
entry.d_ino = ino;
strcpy(entry.d_name, name);
appendData(dir, TYPE_DIRECTORY, (unsigned char *) &entry, sizeof(Dirent));
}
 
 
void createFile(Inode *parent) {
Inode in;
int i;
char c;
FILE *f;
unsigned char buf[BSIZE];
 
/* get mode, uid and gid */
getStr();
in.i_mode = getMode(string[0], "-bcd", IFREG, IFBLK, IFCHR, IFDIR);
in.i_mode |= getMode(string[1], "-u", 0, ISUID, 0, 0);
in.i_mode |= getMode(string[2], "-g", 0, ISGID, 0, 0);
for (i = 3; i < 6; i++) {
c = string[i];
if (c < '0' || c > '7') {
error("%c/%s: bad octal mode digit", c, string);
}
in.i_mode |= (c - '0') << (15 - 3 * i);
}
in.i_uid = getNum();
in.i_gid = getNum();
/* general initialization prior to switching on format */
lastIno++;
in.i_number = lastIno;
in.i_nlink = 1;
in.i_size = 0;
for (i = 0; i < NADDR; i++) {
in.i_addr[i] = 0;
}
if (parent == NULL) {
parent = &in;
in.i_nlink--;
}
/* now switch on format */
switch (in.i_mode & IFMT) {
case IFREG:
/* regular file:
contents is a file name */
getStr();
f = fopen(string, "rb");
if (f == NULL) {
error("%s: cannot open", string);
}
while ((i = fread(buf, 1, BSIZE, f)) > 0) {
appendData(&in, TYPE_COPY, buf, i);
}
fclose(f);
break;
case IFBLK:
case IFCHR:
/* special file:
contents is major/minor device */
in.i_addr[0] = (getNum() & 0xFFFF) << 16;
in.i_addr[0] |= (getNum() & 0xFFFF);
break;
case IFDIR:
/* directory:
put in extra links, call recursively until name is "$" */
parent->i_nlink++;
in.i_nlink++;
makeDirEntry(&in, in.i_number, ".");
makeDirEntry(&in, parent->i_number, "..");
while (1) {
getStr();
if (string[0] == '$' && string[1] == '\0') {
break;
}
makeDirEntry(&in, lastIno + 1, string);
createFile(&in);
}
break;
default:
error("bad format/mode %o\n", in.i_mode);
break;
}
/* finally write the inode */
iput(&in);
}
 
 
/**************************************************************/
 
 
void showSizes(void) {
printf("BSIZE = %d\n", BSIZE);
printf("NICINOD = %d\n", NICINOD);
printf("NICFREE = %d\n", NICFREE);
printf("NADDR = %d\n", NADDR);
printf("NDADDR = %d\n", NDADDR);
printf("DIRSIZ = %d\n", DIRSIZ);
printf("NIPB = %d\n", NIPB);
printf("NDIRENT = %d\n", NDIRENT);
printf("NINDIR = %d\n", NINDIR);
printf("sizeof(Filsys) = %d\n", sizeof(Filsys));
printf("sizeof(Dinode) = %d\n", sizeof(Dinode));
printf("sizeof(Dirent) = %d\n", sizeof(Dirent));
printf("sizeof(Fblk) = %d\n", sizeof(Fblk));
}
 
 
int main(int argc, char *argv[]) {
char *fsnam;
char *proto;
char protoBuf[20];
unsigned long fsSize;
int part;
char *endptr;
unsigned char partTable[SSIZE];
unsigned char *ptptr;
unsigned long partType;
EOS32_daddr_t maxBlocks;
EOS32_daddr_t numBlocks;
EOS32_ino_t numInodes;
int i;
char c;
FILE *bootblk;
long bootblkSize;
unsigned char buf[BSIZE];
 
if (argc == 2 && strcmp(argv[1], "--sizes") == 0) {
showSizes();
exit(0);
}
if (argc != 3 && argc != 4) {
printf("Usage: %s <disk> <partition or '*'> [<prototype or size>]\n",
argv[0]);
printf(" or: %s --sizes\n", argv[0]);
exit(1);
}
time(&now);
fsnam = argv[1];
fs = fopen(fsnam, "r+b");
if (fs == NULL) {
error("cannot open disk image '%s'", fsnam);
}
if (strcmp(argv[2], "*") == 0) {
/* whole disk contains one single file system */
fsStart = 0;
fseek(fs, 0, SEEK_END);
fsSize = ftell(fs) / SSIZE;
} else {
/* argv[2] is partition number of file system */
part = strtoul(argv[2], &endptr, 10);
if (*endptr != '\0' || part < 0 || part > 15) {
error("illegal partition number '%s'", argv[2]);
}
fseek(fs, 1 * SSIZE, SEEK_SET);
if (fread(partTable, 1, SSIZE, fs) != SSIZE) {
error("cannot read partition table of disk '%s'", fsnam);
}
ptptr = partTable + part * 32;
partType = read4FromEco(ptptr + 0);
if ((partType & 0x7FFFFFFF) != 0x00000058) {
error("partition %d of disk '%s' does not contain an EOS32 file system",
part, fsnam);
}
fsStart = read4FromEco(ptptr + 4);
fsSize = read4FromEco(ptptr + 8);
}
printf("File system space is %lu (0x%lX) sectors of %d bytes each.\n",
fsSize, fsSize, SSIZE);
if (fsSize % SPB != 0) {
printf("File system space is not a multiple of block size.\n");
}
maxBlocks = fsSize / SPB;
printf("This equals %lu (0x%lX) blocks of %d bytes each.\n",
maxBlocks, maxBlocks, BSIZE);
if (argc == 4) {
proto = argv[3];
} else {
proto = protoBuf;
sprintf(protoBuf, "%lu", maxBlocks);
}
/* initialize super block and possibly write boot block */
filsys.s_magic = SUPER_MAGIC;
fin = fopen(proto, "rt");
if (fin == NULL) {
/* cannot open prototype file, perhaps size was specified */
charp = "d--777 0 0 $ ";
numBlocks = 0;
for (i = 0; (c = proto[i]) != '\0'; i++) {
if (c < '0' || c > '9') {
/* neither valid prototype file nor valid size */
error("cannot open prototype '%s'", proto);
}
numBlocks = numBlocks * 10 + (c - '0');
}
numInodes = (numBlocks * BSIZE) / AFS;
} else {
/* prototype file opened */
charp = NULL;
getStr();
if (strcmp(string, "-noboot-") == 0) {
/* boot block not wanted */
} else {
/* string holds the name of the boot block file */
bootblk = fopen(string, "rb");
if (bootblk == NULL) {
error("cannot open boot block file '%s'", string);
}
fseek(bootblk, 0, SEEK_END);
bootblkSize = ftell(bootblk);
fseek(bootblk, 0, SEEK_SET);
if (bootblkSize > BSIZE) {
error("boot block file '%s' is bigger than a block", string);
}
for (i = 0; i < BSIZE; i++) {
buf[i] = '\0';
}
if (fread(buf, 1, bootblkSize, bootblk) != bootblkSize) {
error("cannot read boot block file '%s'", string);
}
wtfs(0, buf, TYPE_COPY);
fclose(bootblk);
}
numBlocks = getNum();
numInodes = getNum();
}
if (numBlocks > maxBlocks) {
error("file system exceeds available space");
}
if (numBlocks < maxBlocks) {
printf("File system does not fully utilize available space.\n");
}
filsys.s_fsize = numBlocks;
filsys.s_isize = (numInodes + NIPB - 1) / NIPB;
numInodes = filsys.s_isize * NIPB;
if (2 + filsys.s_isize >= filsys.s_fsize) {
error("bad block ratio (total/inode = %lu/%lu)",
filsys.s_fsize, filsys.s_isize);
}
printf("File system size = %ld blocks\n", filsys.s_fsize);
printf("Number of inodes = %ld inodes\n", numInodes);
filsys.s_freeblks = 0;
filsys.s_freeinos = 0;
filsys.s_ninode = 0;
for (i = 0; i < NICINOD; i++) {
filsys.s_inode[i] = 0;
}
filsys.s_nfree = 0;
for (i = 0; i < NICFREE; i++) {
filsys.s_free[i] = 0;
}
filsys.s_time = now;
filsys.s_flock = 0;
filsys.s_ilock = 0;
filsys.s_fmod = 0;
filsys.s_ronly = 0;
/* init inodes */
initInodes();
/* init free list */
initFreeList();
/* create files */
createFile(NULL);
/* fill free inode list in super block */
/* note: this isn't strictly necessary, but cuts down file
creation time within the newly created partition or disk */
fillFreeInodeList(numInodes);
/* finally write super block and return */
wtfs(1, (unsigned char *) &filsys, TYPE_SUPER);
return 0;
}
/disk/tools/fs-EOS32/mkfs/root.fsys
0,0 → 1,27
./bootblk
2236 1500
d--755 1 1
boot d--755 2 1
hello.bin ---644 2 1 ../../stdalone/hello.bin
hello2.bin ---644 2 1 ../../stdalone/hello2.bin
memsize.bin ---644 2 1 ../../stdalone/memsize.bin
onetask.bin ---644 2 1 ../../stdalone/onetask.bin
twotasks-1.bin ---644 2 1 ../../stdalone/twotasks-1.bin
twotasks-2.bin ---644 2 1 ../../stdalone/twotasks-2.bin
wrtmbr.bin ---644 2 1 ../../stdalone/wrtmbr.bin
dskchk.bin ---644 2 1 ../../stdalone/dskchk.bin
mkpart.bin ---644 2 1 ../../stdalone/mkpart.bin
shpart.bin ---644 2 1 ../../stdalone/shpart.bin
eos32.bin ---644 2 1 ../../../os-bin/EOS32/eos32.bin
$
bin d--755 2 1
$
dev d--755 2 1
$
etc d--755 2 1
$
tmp d--777 2 1
$
usr d--755 2 1
$
$
/disk/tools/fs-EOS32/mkfs/usr.fsys
0,0 → 1,22
-noboot-
6000 4000
d--755 2 1
data d--777 2 1
1 ---644 5 5 ../../data/0x000001
2 ---644 5 5 ../../data/0x000002
4 ---644 5 5 ../../data/0x000004
8 ---644 5 5 ../../data/0x000008
10 ---644 5 5 ../../data/0x000010
20 ---644 5 5 ../../data/0x000020
40 ---644 5 5 ../../data/0x000040
80 ---644 5 5 ../../data/0x000080
100 ---644 5 5 ../../data/0x000100
200 ---644 5 5 ../../data/0x000200
400 ---644 5 5 ../../data/0x000400
800 ---644 5 5 ../../data/0x000800
$
hellwig d--755 6 1
$
src d--755 7 1
$
$
/disk/tools/fs-EOS32/mkfs/Makefile
0,0 → 1,39
#
# Makefile for mkfs utility
#
 
BUILD = ../../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = mkfs.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = EOS32-mkfs
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
mkdir -p $(BUILD)/run/fs-EOS32
cp root.fsys $(BUILD)/run/fs-EOS32
cp usr.fsys $(BUILD)/run/fs-EOS32
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/tools/fs-EOS32/Makefile.run
0,0 → 1,12
#
# Makefile for building an EOS32 file system
#
 
BUILD = ../..
 
all:
$(BUILD)/bin/EOS32-mkfs ../disk.img 0 root.fsys
$(BUILD)/bin/EOS32-mkfs ../disk.img 2 usr.fsys
 
clean:
rm -f *~
/disk/tools/fs-EOS32/shfs/shfs.c
0,0 → 1,658
/*
* shfs.c -- show an EOS32 file system
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
 
 
#define SECTOR_SIZE 512 /* disk sector size in bytes */
#define BLOCK_SIZE 4096 /* disk block size in bytes */
#define SPB (BLOCK_SIZE / SECTOR_SIZE)
#define LINE_SIZE 100 /* input line buffer size in bytes */
#define LINES_PER_BATCH 32 /* number of lines output in one batch */
 
#define NICINOD 500 /* number of free inodes in superblock */
#define NICFREE 500 /* number of free blocks in superblock */
#define INOPB 64 /* number of inodes per block */
#define DIRPB 64 /* number of directory entries per block */
#define DIRSIZ 60 /* max length of path name component */
 
#define IFMT 070000 /* type of file */
#define IFREG 040000 /* regular file */
#define IFDIR 030000 /* directory */
#define IFCHR 020000 /* character special */
#define IFBLK 010000 /* block special */
#define IFFREE 000000 /* reserved (indicates free inode) */
#define ISUID 004000 /* set user id on execution */
#define ISGID 002000 /* set group id on execution */
#define ISVTX 001000 /* save swapped text even after use */
#define IUREAD 000400 /* user's read permission */
#define IUWRITE 000200 /* user's write permission */
#define IUEXEC 000100 /* user's execute permission */
#define IGREAD 000040 /* group's read permission */
#define IGWRITE 000020 /* group's write permission */
#define IGEXEC 000010 /* group's execute permission */
#define IOREAD 000004 /* other's read permission */
#define IOWRITE 000002 /* other's write permission */
#define IOEXEC 000001 /* other's execute permission */
 
 
typedef unsigned long EOS32_ino_t;
typedef unsigned long EOS32_daddr_t;
typedef unsigned long EOS32_off_t;
typedef long EOS32_time_t;
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
printf("Error: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
exit(1);
}
 
 
unsigned long fsStart; /* file system start sector */
 
 
void readBlock(FILE *disk,
EOS32_daddr_t blockNum,
unsigned char *blockBuffer) {
fseek(disk, fsStart * SECTOR_SIZE + blockNum * BLOCK_SIZE, SEEK_SET);
if (fread(blockBuffer, BLOCK_SIZE, 1, disk) != 1) {
error("cannot read block %lu (0x%lX)", blockNum, blockNum);
}
}
 
 
unsigned long get4Bytes(unsigned char *addr) {
return (unsigned long) addr[0] << 24 |
(unsigned long) addr[1] << 16 |
(unsigned long) addr[2] << 8 |
(unsigned long) addr[3] << 0;
}
 
 
int waitForReturn(void) {
char line[LINE_SIZE];
 
printf("press <enter> to continue, <esc> to break, q to quit: ");
fflush(stdout);
if (fgets(line, LINE_SIZE, stdin) == NULL) {
printf("\n");
exit(0);
}
if (line[0] == 'q') {
exit(0);
}
if (line[0] == 0x1B) {
return 1;
}
return 0;
}
 
 
int checkBatch(int numLines) {
static int lines;
int r;
 
r = 0;
if (numLines == 0) {
/* initialize */
lines = 0;
} else {
/* output numLines lines */
lines += numLines;
if (lines >= LINES_PER_BATCH) {
r = waitForReturn();
lines = 0;
}
}
return r;
}
 
 
void rawBlock(unsigned char *p) {
int i, j;
unsigned char c;
 
checkBatch(0);
for (i = 0; i < BLOCK_SIZE / 16; i++) {
printf("%04X ", i * 16);
for (j = 0; j < 16; j++) {
c = p[i * 16 + j];
printf("%02X ", c);
}
printf(" ");
for (j = 0; j < 16; j++) {
c = p[i * 16 + j];
if (c < 0x20 || c >= 0x7F) {
printf(".");
} else {
printf("%c", c);
}
}
printf("\n");
if (checkBatch(1)) return;
}
}
 
 
void superBlock(unsigned char *p) {
unsigned int magic;
EOS32_daddr_t fsize;
EOS32_daddr_t isize;
EOS32_daddr_t freeblks;
EOS32_ino_t freeinos;
unsigned int ninode;
EOS32_ino_t ino;
unsigned int nfree;
EOS32_daddr_t free;
EOS32_time_t tim;
char *dat;
unsigned char flag;
int i;
 
checkBatch(0);
magic = get4Bytes(p);
p += 4;
printf("magic number = %u (0x%08X)\n", magic, magic);
if (checkBatch(1)) return;
fsize = get4Bytes(p);
p += 4;
printf("file system size = %lu (0x%lX) blocks\n", fsize, fsize);
if (checkBatch(1)) return;
isize = get4Bytes(p);
p += 4;
printf("inode list size = %lu (0x%lX) blocks\n", isize, isize);
if (checkBatch(1)) return;
freeblks = get4Bytes(p);
p += 4;
printf("free blocks = %lu (0x%lX)\n", freeblks, freeblks);
if (checkBatch(1)) return;
freeinos = get4Bytes(p);
p += 4;
printf("free inodes = %lu (0x%lX)\n", freeinos, freeinos);
if (checkBatch(1)) return;
ninode = get4Bytes(p);
p += 4;
printf("number of entries in free inode list = %u (0x%X)\n", ninode, ninode);
if (checkBatch(1)) return;
for (i = 0; i < NICINOD; i++) {
ino = get4Bytes(p);
p += 4;
if (i < ninode) {
printf(" free inode[%3d] = %lu (0x%lX)\n", i, ino, ino);
if (checkBatch(1)) return;
}
}
nfree = get4Bytes(p);
p += 4;
printf("number of entries in free block list = %u (0x%X)\n", nfree, nfree);
if (checkBatch(1)) return;
for (i = 0; i < NICFREE; i++) {
free = get4Bytes(p);
p += 4;
if (i < nfree) {
printf(" %s block[%3d] = %lu (0x%lX)\n",
i == 0 ? "link" : "free", i, free, free);
if (checkBatch(1)) return;
}
}
tim = get4Bytes(p);
p += 4;
dat = ctime((time_t *) &tim);
dat[strlen(dat) - 1] = '\0';
printf("last super block update = %ld (%s)\n", tim, dat);
if (checkBatch(1)) return;
flag = *p++;
printf("free list locked flag = %d\n", (int) flag);
if (checkBatch(1)) return;
flag = *p++;
printf("inode list locked flag = %d\n", (int) flag);
if (checkBatch(1)) return;
flag = *p++;
printf("super block modified flag = %d\n", (int) flag);
if (checkBatch(1)) return;
flag = *p++;
printf("fs mounted read-only flag = %d\n", (int) flag);
if (checkBatch(1)) return;
}
 
 
void inodeBlock(unsigned char *p) {
unsigned int mode;
unsigned int nlink;
unsigned int uid;
unsigned int gid;
EOS32_time_t tim;
char *dat;
EOS32_off_t size;
EOS32_daddr_t addr;
int i, j;
 
checkBatch(0);
for (i = 0; i < INOPB; i++) {
printf("inode %d:", i);
mode = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" type/mode = 0x%08X = ", mode);
if ((mode & IFMT) == IFREG) {
printf("-");
} else
if ((mode & IFMT) == IFDIR) {
printf("d");
} else
if ((mode & IFMT) == IFCHR) {
printf("c");
} else
if ((mode & IFMT) == IFBLK) {
printf("b");
} else {
printf("?");
}
printf("%c", mode & IUREAD ? 'r' : '-');
printf("%c", mode & IUWRITE ? 'w' : '-');
printf("%c", mode & IUEXEC ? 'x' : '-');
printf("%c", mode & IGREAD ? 'r' : '-');
printf("%c", mode & IGWRITE ? 'w' : '-');
printf("%c", mode & IGEXEC ? 'x' : '-');
printf("%c", mode & IOREAD ? 'r' : '-');
printf("%c", mode & IOWRITE ? 'w' : '-');
printf("%c", mode & IOEXEC ? 'x' : '-');
if (mode & ISUID) {
printf(", set uid");
}
if (mode & ISGID) {
printf(", set gid");
}
if (mode & ISVTX) {
printf(", save text");
}
} else {
printf(" <free>");
}
printf("\n");
if (checkBatch(1)) return;
nlink = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" nlnk = %u (0x%08X)\n", nlink, nlink);
if (checkBatch(1)) return;
}
uid = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" uid = %u (0x%08X)\n", uid, uid);
if (checkBatch(1)) return;
}
gid = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" gid = %u (0x%08X)\n", gid, gid);
if (checkBatch(1)) return;
}
tim = get4Bytes(p);
p += 4;
dat = ctime((time_t *) &tim);
dat[strlen(dat) - 1] = '\0';
if (mode != 0) {
printf(" time inode created = %ld (%s)\n", tim, dat);
if (checkBatch(1)) return;
}
tim = get4Bytes(p);
p += 4;
dat = ctime((time_t *) &tim);
dat[strlen(dat) - 1] = '\0';
if (mode != 0) {
printf(" time last modified = %ld (%s)\n", tim, dat);
if (checkBatch(1)) return;
}
tim = get4Bytes(p);
p += 4;
dat = ctime((time_t *) &tim);
dat[strlen(dat) - 1] = '\0';
if (mode != 0) {
printf(" time last accessed = %ld (%s)\n", tim, dat);
if (checkBatch(1)) return;
}
size = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" size = %lu (0x%lX)\n", size, size);
if (checkBatch(1)) return;
}
for (j = 0; j < 6; j++) {
addr = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" direct block[%1d] = %lu (0x%lX)\n", j, addr, addr);
if (checkBatch(1)) return;
}
}
addr = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" single indirect = %lu (0x%lX)\n", addr, addr);
if (checkBatch(1)) return;
}
addr = get4Bytes(p);
p += 4;
if (mode != 0) {
printf(" double indirect = %lu (0x%lX)\n", addr, addr);
if (checkBatch(1)) return;
}
}
}
 
 
void directoryBlock(unsigned char *p) {
EOS32_ino_t ino;
int i, j;
unsigned char c;
 
checkBatch(0);
for (i = 0; i < DIRPB; i++) {
printf("%02d: ", i);
ino = get4Bytes(p);
p += 4;
printf("inode = %lu (0x%lX)\n", ino, ino);
if (checkBatch(1)) return;
printf(" name = ");
if (*p == '\0') {
printf("<empty>");
} else {
for (j = 0; j < DIRSIZ; j++) {
c = *(p + j);
if (c == '\0') {
break;
}
if (c < 0x20 || c >= 0x7F) {
printf(".");
} else {
printf("%c", c);
}
}
}
printf("\n");
if (checkBatch(1)) return;
p += DIRSIZ;
}
}
 
 
void freeBlock(unsigned char *p) {
unsigned int nfree;
EOS32_daddr_t addr;
int i;
 
checkBatch(0);
nfree = get4Bytes(p);
p += 4;
printf("nfree = %u (0x%X)\n", nfree, nfree);
if (checkBatch(1)) return;
for (i = 0; i < NICFREE; i++) {
addr = get4Bytes(p);
p += 4;
if (i < nfree) {
printf(" %s block[%3d] = %lu (0x%lX)\n",
i == 0 ? "link" : "free", i, addr, addr);
if (checkBatch(1)) return;
}
}
}
 
 
void indirectBlock(unsigned char *p) {
EOS32_daddr_t addr;
int i;
 
checkBatch(0);
for (i = 0; i < BLOCK_SIZE / sizeof(EOS32_daddr_t); i++) {
addr = get4Bytes(p);
p += 4;
printf("block[%4d] = %lu (0x%lX)\n", i, addr, addr);
if (checkBatch(1)) return;
}
}
 
 
void help(void) {
printf("Commands are:\n");
printf(" h help\n");
printf(" q quit\n");
printf(" r show block as raw data\n");
printf(" s show block as super block\n");
printf(" i show block as inode block\n");
printf(" d show block as directory block\n");
printf(" f show block as block on the free list\n");
printf(" * show block as indirect block\n");
printf(" b <num> set current block to <num>\n");
printf(" + increment current block\n");
printf(" - decrement current block\n");
printf(" t <num> translate inode <num> to block number\n");
printf(" and relative inode number within block\n");
}
 
 
int parseNumber(char **pc, unsigned long *pi) {
char *p;
unsigned int base, dval;
unsigned long n;
 
p = *pc;
while (*p == ' ' || *p == '\t') {
p++;
}
if (*p == '\0' || *p == '\n') {
printf("Error: number is missing!\n");
return 0;
}
base = 10;
if (*p == '0') {
p++;
if (*p != '\0' && *p != '\n') {
if (*p == 'x' || *p == 'X') {
base = 16;
p++;
} else {
base = 8;
}
}
}
n = 0;
while ((*p >= '0' && *p <= '9') ||
(*p >= 'a' && *p <= 'f') ||
(*p >= 'A' && *p <= 'F')) {
if (*p >= '0' && *p <= '9') {
dval = (*p - '0');
} else
if (*p >= 'a' && *p <= 'f') {
dval = (*p - 'a' + 10);
} else
if (*p >= 'A' && *p <= 'F') {
dval = (*p - 'A' + 10);
}
if (dval >= base) {
printf("Error: digit value %d is illegal in number base %d\n",
dval, base);
return 0;
}
n *= base;
n += dval;
p++;
}
while (*p == ' ' || *p == '\t') {
p++;
}
*pc = p;
*pi = n;
return 1;
}
 
 
int main(int argc, char *argv[]) {
FILE *disk;
unsigned long fsSize;
int part;
char *endptr;
unsigned char partTable[SECTOR_SIZE];
unsigned char *ptptr;
unsigned long partType;
EOS32_daddr_t numBlocks;
EOS32_daddr_t currBlock;
unsigned char blockBuffer[BLOCK_SIZE];
char line[LINE_SIZE];
int quit;
char *p;
unsigned long n;
 
if (argc != 3) {
printf("Usage: %s <disk> <partition>\n", argv[0]);
printf(" <disk> is a disk image file name\n");
printf(" <partition> is a partition number ");
printf("(or '*' for the whole disk)\n");
exit(1);
}
disk = fopen(argv[1], "rb");
if (disk == NULL) {
error("cannot open disk image file '%s'", argv[1]);
}
if (strcmp(argv[2], "*") == 0) {
/* whole disk contains one single file system */
fsStart = 0;
fseek(disk, 0, SEEK_END);
fsSize = ftell(disk) / SECTOR_SIZE;
} else {
/* argv[2] is partition number of file system */
part = strtoul(argv[2], &endptr, 10);
if (*endptr != '\0' || part < 0 || part > 15) {
error("illegal partition number '%s'", argv[2]);
}
fseek(disk, 1 * SECTOR_SIZE, SEEK_SET);
if (fread(partTable, 1, SECTOR_SIZE, disk) != SECTOR_SIZE) {
error("cannot read partition table of disk '%s'", argv[1]);
}
ptptr = partTable + part * 32;
partType = get4Bytes(ptptr + 0);
if ((partType & 0x7FFFFFFF) != 0x00000058) {
error("partition %d of disk '%s' does not contain an EOS32 file system",
part, argv[1]);
}
fsStart = get4Bytes(ptptr + 4);
fsSize = get4Bytes(ptptr + 8);
}
printf("File system has size %lu (0x%lX) sectors of %d bytes each.\n",
fsSize, fsSize, SECTOR_SIZE);
if (fsSize % SPB != 0) {
printf("File system size is not a multiple of block size.\n");
}
numBlocks = fsSize / SPB;
printf("This equals %lu (0x%lX) blocks of %d bytes each.\n",
numBlocks, numBlocks, BLOCK_SIZE);
if (numBlocks < 2) {
error("file system has less than 2 blocks");
}
currBlock = 1;
readBlock(disk, currBlock, blockBuffer);
help();
quit = 0;
while (!quit) {
printf("shfs [block %lu (0x%lX)] > ", currBlock, currBlock);
fflush(stdout);
if (fgets(line, LINE_SIZE, stdin) == NULL) {
printf("\n");
break;
}
if (line[0] == '\0' || line[0] == '\n') {
continue;
}
switch (line[0]) {
case 'h':
case '?':
help();
break;
case 'q':
quit = 1;
break;
case 'r':
rawBlock(blockBuffer);
break;
case 's':
superBlock(blockBuffer);
break;
case 'i':
inodeBlock(blockBuffer);
break;
case 'd':
directoryBlock(blockBuffer);
break;
case 'f':
freeBlock(blockBuffer);
break;
case '*':
indirectBlock(blockBuffer);
break;
case 'b':
p = line + 1;
if (!parseNumber(&p, &n)) {
break;
}
if (*p != '\0' && *p != '\n') {
printf("Error: cannot parse block number!\n");
break;
}
if (n >= numBlocks) {
printf("Error: block number too big for file system!\n");
break;
}
currBlock = n;
readBlock(disk, currBlock, blockBuffer);
break;
case '+':
n = currBlock + 1;
if (n >= numBlocks) {
printf("Error: block number too big for file system!\n");
break;
}
currBlock = n;
readBlock(disk, currBlock, blockBuffer);
break;
case '-':
n = currBlock - 1;
if (n >= numBlocks) {
printf("Error: block number too big for file system!\n");
break;
}
currBlock = n;
readBlock(disk, currBlock, blockBuffer);
break;
case 't':
p = line + 1;
if (!parseNumber(&p, &n)) {
break;
}
if (*p != '\0' && *p != '\n') {
printf("Error: cannot parse inode number!\n");
break;
}
printf("inode %lu (0x%lX) is in block %lu (0x%lX), inode %lu\n",
n, n, n / INOPB + 2, n / INOPB + 2, n % INOPB);
break;
default:
printf("Unknown command, type 'h' for help!\n");
break;
}
}
fclose(disk);
return 0;
}
/disk/tools/fs-EOS32/shfs/Makefile
0,0 → 1,36
#
# Makefile for shfs utility
#
 
BUILD = ../../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = shfs.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = EOS32-shfs
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/tools/fs-EOS32/mkboot/stage1/br.s
0,0 → 1,128
;
; br.s -- the boot record
;
 
; Runtime environment:
;
; This code must be loaded and started at 0xC0000000.
; It allocates a stack from 0xC0001000 downwards. So
; it must run within 4K (code + data + stack).
;
; This code expects the disk number of the boot disk
; in $16, the start sector of the disk or partition
; to be booted in $17 and its size in $18.
;
; The boot loader, which is loaded by this code,
; must be in standalone (headerless) executable
; format, stored at partition relative disk
; sectors 1..7 (i.e., the boot block), and
; gets loaded and started at 0xC0300000.
 
.set stacktop,0xC0001000 ; top of stack
.set loadaddr,0xC0300000 ; where to load the boot loader
 
.set cout,0xE0000018 ; ROM console output
.set dskio,0xE0000030 ; ROM disk I/O
 
; reset arrives here
reset:
j start
 
; interrupts arrive here
intrpt:
j userMiss
 
; user TLB misses arrive here
userMiss:
add $4,$0,intmsg ; we do not expect any interrupt
jal msgout
j halt
 
; load the boot loader and start it
start:
add $29,$0,stacktop ; setup stack
add $4,$0,strtmsg ; say what is going on
jal msgout
add $4,$0,1 ; start loading with sector 1
add $5,$0,loadaddr ; where to load the boot loader
and $5,$5,0x3FFFFFFF ; convert to physical address
add $6,$0,7 ; 7 sectors to load
jal rdsct
add $8,$0,loadaddr ; start executing the boot loader
jr $8
 
; read disk sectors
; $4 start sector number (disk or partition relative)
; $5 transfer address
; $6 number of sectors
rdsct:
sub $29,$29,32
stw $31,$29,20
stw $6,$29,16 ; sector count
add $7,$5,$0 ; transfer address
add $6,$4,$17 ; relative sector -> absolute
add $5,$0,'r' ; command
add $4,$0,$16 ; disk number
add $8,$0,dskio
jalr $8
bne $2,$0,rderr ; error?
ldw $31,$29,20
add $29,$29,32
jr $31
 
; disk read error
rderr:
add $4,$0,dremsg
jal msgout
j halt
 
; output message
; $4 pointer to string
msgout:
sub $29,$29,8
stw $31,$29,4
stw $16,$29,0
add $16,$4,0 ; $16: pointer to string
msgout1:
ldbu $4,$16,0 ; get character
beq $4,$0,msgout2 ; done?
jal chrout ; output character
add $16,$16,1 ; bump pointer
j msgout1 ; continue
msgout2:
ldw $16,$29,0
ldw $31,$29,4
add $29,$29,8
jr $31
 
; output character
; $4 character
chrout:
sub $29,$29,4
stw $31,$29,0
add $8,$0,cout
jalr $8
ldw $31,$29,0
add $29,$29,4
jr $31
 
; halt execution by looping
halt:
add $4,$0,hltmsg
jal msgout
halt1:
j halt1
 
; messages
intmsg:
.byte "unexpected interrupt", 0x0D, 0x0A, 0
strtmsg:
.byte "BR executing...", 0x0D, 0x0A, 0
dremsg:
.byte "disk read error", 0x0D, 0x0A, 0
hltmsg:
.byte "bootstrap halted", 0x0D, 0x0A, 0
 
; boot record signature
.locate 512-2
.byte 0x55, 0xAA
/disk/tools/fs-EOS32/mkboot/stage1/Makefile
0,0 → 1,16
#
# Makefile to build the boot record
#
 
BUILD = ../../../../../build
 
all: br.bin
 
br.bin: br.o
$(BUILD)/bin/ld -h -rc 0xC0000000 -o br.bin br.o
 
br.o: br.s
$(BUILD)/bin/as -o br.o br.s
 
clean:
rm -f *~ br.o br.bin
/disk/tools/fs-EOS32/mkboot/stage2/biolib.s
0,0 → 1,26
;
; biolib.s -- basic I/O library
;
 
.set cin,0xE0000010
.set cout,0xE0000018
.set dskio,0xE0000030
 
.export getc
.export putc
.export rwscts
 
.code
.align 4
 
getc:
add $8,$0,cin
jr $8
 
putc:
add $8,$0,cout
jr $8
 
rwscts:
add $8,$0,dskio
jr $8
/disk/tools/fs-EOS32/mkboot/stage2/c0.s
0,0 → 1,59
;
; c0.s -- startup code and begin-of-segment labels
;
 
.import main
 
.import _ecode
.import _edata
.import _ebss
 
.export _bcode
.export _bdata
.export _bbss
 
.import bootDisk
.import startSector
.import numSectors
.import entryPoint
 
.code
_bcode:
 
start:
add $10,$0,_bdata ; copy data segment
add $8,$0,_edata
sub $9,$8,$10
add $9,$9,_ecode
j cpytest
cpyloop:
ldw $11,$9,0
stw $11,$8,0
cpytest:
sub $8,$8,4
sub $9,$9,4
bgeu $8,$10,cpyloop
add $8,$0,_bbss ; clear bss segment
add $9,$0,_ebss
j clrtest
clrloop:
stw $0,$8,0
add $8,$8,4
clrtest:
bltu $8,$9,clrloop
add $29,$0,0xC0400000 ; setup stack
stw $16,$0,bootDisk ; make arguments available
stw $17,$0,startSector
stw $18,$0,numSectors
jal main ; call 'main' function
ldw $16,$0,bootDisk ; setup arguments for next stage
ldw $17,$0,startSector
ldw $18,$0,numSectors
ldw $31,$0,entryPoint ; jump to loaded program
jr $31
 
.data
_bdata:
 
.bss
_bbss:
/disk/tools/fs-EOS32/mkboot/stage2/boot.c
0,0 → 1,444
/*
* boot.c -- the bootstrap (boot loader)
*/
 
 
#include "biolib.h"
 
 
/**************************************************************/
 
/* constants and data types */
 
 
#define DFLT_KERNEL "/boot/eos32.bin" /* path of default OS kernel */
#define LOAD_ADDR 0xC0000000 /* where to load the kernel */
 
#define MAX_LINE 100 /* line buffer size */
 
#define EXEC_MAGIC 0x3AE82DD4 /* magic number for executables */
 
#define PSHIFT 12 /* ld of page size */
#define PSIZE (1 << PSHIFT) /* page size in bytes */
#define PMASK (PSIZE - 1) /* page mask */
 
#define BSHIFT 12 /* ld of block size */
#define BSIZE (1 << BSHIFT) /* disk block size in bytes */
#define BMASK (BSIZE - 1) /* block mask */
 
#define SSIZE 512 /* disk sector size in bytes */
#define SPB (BSIZE / SSIZE) /* sectors per block */
 
#define ROOT_INO 1 /* inode number of root directory */
#define NADDR 8 /* number of block addresses in inode */
#define NDADDR 6 /* number of direct block addresses */
#define DIRSIZ 60 /* max length of path name component */
 
#define NIPB (BSIZE / sizeof(Dinode))
#define NDIRENT (BSIZE / sizeof(Dirent))
#define NINDIR (BSIZE / sizeof(EOS32_daddr_t))
 
#define NULL 0
 
 
typedef unsigned long EOS32_ino_t;
typedef unsigned long EOS32_daddr_t;
typedef unsigned long EOS32_off_t;
typedef long EOS32_time_t;
 
 
#define IFMT 070000 /* type of file */
#define IFREG 040000 /* regular file */
#define IFDIR 030000 /* directory */
#define IFCHR 020000 /* character special */
#define IFBLK 010000 /* block special */
#define IFFREE 000000 /* reserved (indicates free inode) */
#define ISUID 004000 /* set user id on execution */
#define ISGID 002000 /* set group id on execution */
#define ISVTX 001000 /* save swapped text even after use */
#define IUREAD 000400 /* user's read permission */
#define IUWRITE 000200 /* user's write permission */
#define IUEXEC 000100 /* user's execute permission */
#define IGREAD 000040 /* group's read permission */
#define IGWRITE 000020 /* group's write permission */
#define IGEXEC 000010 /* group's execute permission */
#define IOREAD 000004 /* other's read permission */
#define IOWRITE 000002 /* other's write permission */
#define IOEXEC 000001 /* other's execute permission */
 
/*
* The following two macros convert an inode number to the disk
* block containing the inode and an inode number within the block.
*/
#define itod(i) (2 + (i) / NIPB)
#define itoo(i) ((i) % NIPB)
 
 
typedef struct {
unsigned int di_mode; /* type and mode of file */
unsigned int di_nlink; /* number of links to file */
unsigned int di_uid; /* owner's user id */
unsigned int di_gid; /* owner's group id */
EOS32_time_t di_ctime; /* time created */
EOS32_time_t di_mtime; /* time last modified */
EOS32_time_t di_atime; /* time last accessed */
EOS32_off_t di_size; /* number of bytes in file */
EOS32_daddr_t di_addr[NADDR]; /* disk block addresses */
} Dinode;
 
 
typedef struct {
EOS32_ino_t d_ino; /* directory inode */
char d_name[DIRSIZ]; /* directory name */
} Dirent;
 
 
/**************************************************************/
 
/* string functions */
 
 
int strlen(char *str) {
int i;
 
i = 0;
while (*str++ != '\0') {
i++;
}
return i;
}
 
 
int strcmp(char *str1, char *str2) {
while (*str1 == *str2) {
if (*str1 == '\0') {
return 0;
}
str1++;
str2++;
}
return (* (unsigned char *) str1) - (* (unsigned char *) str2);
}
 
 
void strcpy(char *dst, char *src) {
while ((*dst++ = *src++) != '\0') ;
}
 
 
/**************************************************************/
 
/* terminal I/O */
 
 
char getchar(void) {
return getc();
}
 
 
void putchar(char c) {
if (c == '\n') {
putchar('\r');
}
putc(c);
}
 
 
void puts(char *s) {
while (*s != '\0') {
putchar(*s++);
}
}
 
 
/**************************************************************/
 
/* get a line from the terminal */
 
 
void getLine(char *prompt, char *line, int max) {
int index;
char c;
 
puts(prompt);
puts(line);
index = strlen(line);
while (1) {
c = getchar();
switch (c) {
case '\r':
putchar('\n');
line[index] = '\0';
return;
case '\b':
case 0x7F:
if (index == 0) {
break;
}
putchar('\b');
putchar(' ');
putchar('\b');
index--;
break;
default:
if (c == '\t') {
c = ' ';
}
if (c < 0x20 || c > 0x7E) {
break;
}
putchar(c);
line[index++] = c;
break;
}
}
}
 
 
/**************************************************************/
 
/* halt with error message */
 
 
void halt(char *msg) {
puts(msg);
puts(", machine halted.\n");
while (1) ;
}
 
 
/**************************************************************/
 
/* disk I/O */
 
 
unsigned int bootDisk = 0; /* gets loaded by previous stage */
unsigned int startSector = 0; /* gets loaded by previous stage */
unsigned int numSectors = 0; /* gets loaded by previous stage */
 
 
/*
* read a disk block
*
* NOTE: buffer must be word-aligned
*/
void readBlock(unsigned int blkno, void *buffer) {
unsigned int sector;
int result;
 
sector = blkno * SPB;
if (sector + SPB > numSectors) {
halt("Sector number exceeds disk or partition size");
}
result = rwscts(bootDisk, 'r', sector + startSector,
(unsigned int) buffer & 0x3FFFFFFF, SPB);
if (result != 0) {
halt("Load error");
}
}
 
 
/**************************************************************/
 
/* file operations*/
 
 
EOS32_daddr_t sibn = -1;
EOS32_daddr_t singleIndirectBlock[NINDIR];
EOS32_daddr_t dibn = -1;
EOS32_daddr_t doubleIndirectBlock[NINDIR];
 
 
/*
* read a block of a file
*
* NOTE: addr must be word-aligned
*/
void readFileBlock(Dinode *ip, int blkno, void *addr) {
EOS32_daddr_t diskBlock;
 
if (blkno < NDADDR) {
/* direct block */
diskBlock = ip->di_addr[blkno];
} else
if (blkno < NDADDR + NINDIR) {
/* single indirect block */
diskBlock = ip->di_addr[NDADDR];
if (sibn != diskBlock) {
readBlock(diskBlock, singleIndirectBlock);
sibn = diskBlock;
}
diskBlock = singleIndirectBlock[blkno - NDADDR];
} else {
/* double indirect block */
diskBlock = ip->di_addr[NDADDR + 1];
if (dibn != diskBlock) {
readBlock(diskBlock, doubleIndirectBlock);
dibn = diskBlock;
}
diskBlock = doubleIndirectBlock[(blkno - NDADDR - NINDIR) / NINDIR];
if (sibn != diskBlock) {
readBlock(diskBlock, singleIndirectBlock);
sibn = diskBlock;
}
diskBlock = singleIndirectBlock[(blkno - NDADDR - NINDIR) % NINDIR];
}
readBlock(diskBlock, addr);
}
 
 
/**************************************************************/
 
/* inode handling */
 
 
Dinode inodeBlock[NIPB];
 
 
Dinode *getInode(unsigned int inode) {
unsigned int bnum;
unsigned int inum;
 
bnum = itod(inode);
inum = itoo(inode);
readBlock(bnum, inodeBlock);
return &inodeBlock[inum];
}
 
 
/**************************************************************/
 
/* convert path to inode */
 
 
Dirent directoryBlock[NDIRENT];
 
 
Dinode *pathToInode(char *path) {
Dinode *ip;
char c;
char dirBuffer[DIRSIZ];
char *cp;
EOS32_off_t offset;
Dirent *dp;
unsigned int ino;
 
/* get root inode */
ip = getInode(ROOT_INO);
/* traverse file system tree while matching path components */
c = *path++;
while (1) {
/* skip leading slashes in path component */
while (c == '/') {
c = *path++;
}
if (c == '\0') {
/* no more path components */
break;
}
/* if there is another component, gather up its name */
cp = dirBuffer;
while (c != '/' && c != '\0') {
if (cp < &dirBuffer[DIRSIZ]) {
*cp++ = c;
}
c = *path++;
}
*cp++ = '\0';
/* ip must be a directory */
if ((ip->di_mode & IFMT) != IFDIR) {
return NULL;
}
/* search directory */
offset = 0;
while (1) {
if (offset >= ip->di_size) {
/* component not found */
return NULL;
}
if ((offset & BMASK) == 0) {
/* read the next directory block */
readFileBlock(ip, offset >> BSHIFT, directoryBlock);
dp = directoryBlock;
}
ino = dp->d_ino;
if (ino != 0) {
if (strcmp(dirBuffer, dp->d_name) == 0) {
/* component found */
break;
}
}
/* no match, try next entry */
dp++;
offset += sizeof(Dirent);
}
/* get corresponding inode */
ip = getInode(ino);
/* look for more components */
}
return ip;
}
 
 
/**************************************************************/
 
/* load the kernel */
 
 
void loadKernel(Dinode *ip) {
unsigned int numBlocks;
unsigned int nextBlock;
unsigned char *nextAddr;
 
numBlocks = (ip->di_size + (BSIZE - 1)) / BSIZE;
nextBlock = 0;
nextAddr = (unsigned char *) LOAD_ADDR;
while (numBlocks--) {
readFileBlock(ip, nextBlock, nextAddr);
nextBlock++;
nextAddr += BSIZE;
}
}
 
 
/**************************************************************/
 
/* main program */
 
 
unsigned int entryPoint; /* where to continue from main() */
 
 
int main(void) {
char line[MAX_LINE];
Dinode *ip;
 
puts("Bootstrap loader executing...\n");
strcpy(line, DFLT_KERNEL);
while (1) {
getLine("\nPlease enter path to kernel: ", line, MAX_LINE);
ip = pathToInode(line);
if (ip == NULL) {
puts("'");
puts(line);
puts("' not found\n");
continue;
}
if ((ip->di_mode & IFMT) != IFREG) {
puts("'");
puts(line);
puts("' is not a regular file\n");
continue;
}
break;
}
puts("Loading '");
puts(line);
puts("'...\n");
loadKernel(ip);
puts("Starting '");
puts(line);
puts("'...\n");
entryPoint = LOAD_ADDR;
return 0;
}
/disk/tools/fs-EOS32/mkboot/stage2/c1.s
0,0 → 1,19
;
; c1.s -- end-of-segment labels
;
 
.export _ecode
.export _edata
.export _ebss
 
.code
.align 4
_ecode:
 
.data
.align 4
_edata:
 
.bss
.align 4
_ebss:
/disk/tools/fs-EOS32/mkboot/stage2/biolib.h
0,0 → 1,15
/*
* biolib.h -- basic I/O library
*/
 
 
#ifndef _BIOLIB_H_
#define _BIOLIB_H_
 
 
char getc(void);
void putc(char c);
int rwscts(int dskno, int cmd, int sector, int addr, int count);
 
 
#endif /* _BIOLIB_H_ */
/disk/tools/fs-EOS32/mkboot/stage2/Makefile
0,0 → 1,26
#
# Makefile to build the bootstrap (boot loader)
#
 
BUILD = ../../../../../build
 
all: boot.bin
 
boot.bin: c0.o boot.o biolib.o c1.o
$(BUILD)/bin/ld -h -rc 0xC0300000 -o boot.bin \
c0.o boot.o biolib.o c1.o
 
c0.o: c0.s
$(BUILD)/bin/as -o c0.o c0.s
 
boot.o: boot.c
$(BUILD)/bin/lcc -A -c -o boot.o boot.c
 
biolib.o: biolib.s
$(BUILD)/bin/as -o biolib.o biolib.s
 
c1.o: c1.s
$(BUILD)/bin/as -o c1.o c1.s
 
clean:
rm -f *~ c0.o boot.o biolib.o c1.o boot.bin
/disk/tools/fs-EOS32/mkboot/Makefile
0,0 → 1,27
#
# Makefile to build the boot block
#
 
BUILD = ../../../../build
 
.PHONY: all install clean
 
all: bootblk
 
install: bootblk
mkdir -p $(BUILD)/run/fs-EOS32
cp bootblk $(BUILD)/run/fs-EOS32
 
bootblk: stage1/br.bin stage2/boot.bin
cat stage1/br.bin stage2/boot.bin >bootblk
 
stage1/br.bin:
$(MAKE) -C stage1
 
stage2/boot.bin:
$(MAKE) -C stage2
 
clean:
$(MAKE) -C stage1 clean
$(MAKE) -C stage2 clean
rm -f *~ bootblk
/disk/tools/fs-EOS32/Makefile
0,0 → 1,27
#
# Makefile for EOS32 disk tools
#
 
BUILD = ../../../build
 
DIRS = mkboot mkfs shfs
 
.PHONY: all install clean
 
all:
for i in $(DIRS) ; do \
$(MAKE) -C $$i all ; \
done
 
install:
for i in $(DIRS) ; do \
$(MAKE) -C $$i install ; \
done
mkdir -p $(BUILD)/run/fs-EOS32
cp Makefile.run $(BUILD)/run/fs-EOS32/Makefile
 
clean:
for i in $(DIRS) ; do \
$(MAKE) -C $$i clean ; \
done
rm -f *~
/disk/tools/mkdata/mkdata.c
0,0 → 1,48
/*
* mkdata.c -- generate test data files for file system test
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
 
#define BLOCK_SIZE 4096
 
 
int main(int argc, char *argv[]) {
int j, i, k, m;
char buf[80];
unsigned char block[BLOCK_SIZE];
FILE *dataFile;
 
if (argc != 1) {
printf("Usage: %s\n", argv[0]);
return 1;
}
for (j = 0; j < 12; j++) {
i = 1 << j;
sprintf(buf, "0x%06X", i);
printf("%s\n", buf);
dataFile = fopen(buf, "wb");
if (dataFile == NULL) {
printf("Error: cannot open data file '%s'\n", buf);
return 1;
}
for (m = 0; m < i; m++) {
for (k = 0; k < BLOCK_SIZE; k += 4) {
block[k + 0] = m >> 24;
block[k + 1] = m >> 16;
block[k + 2] = m >> 8;
block[k + 3] = m >> 0;
}
if (fwrite(block, 1, BLOCK_SIZE, dataFile) != BLOCK_SIZE) {
printf("Error: cannot write data file '%s'\n", buf);
return 1;
}
}
fclose(dataFile);
}
return 0;
}
/disk/tools/mkdata/Makefile
0,0 → 1,25
#
# Makefile to generate test data files for file system test
#
 
BUILD = ../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
 
.PHONY: all install clean
 
all: 0x000001
 
install: 0x000001
mkdir -p $(BUILD)/data
cp 0x* $(BUILD)/data
 
0x000001: mkdata
./mkdata
 
mkdata: mkdata.c
$(CC) $(CFLAGS) -o mkdata mkdata.c
 
clean:
rm -f *~ mkdata 0x*
/disk/tools/shpart/shpart.c
0,0 → 1,143
/*
* shpart.c -- show partitions on a disk
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
 
 
#define SECTOR_SIZE 512
#define NPE (SECTOR_SIZE / sizeof(PartEntry))
#define DESCR_SIZE 20
 
 
typedef struct {
unsigned long type;
unsigned long start;
unsigned long size;
char descr[DESCR_SIZE];
} PartEntry;
 
PartEntry ptr[NPE];
 
 
/**************************************************************/
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
printf("Error: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
exit(1);
}
 
 
/**************************************************************/
 
 
unsigned long getNumber(unsigned char *p) {
return (unsigned long) *(p + 0) << 24 |
(unsigned long) *(p + 1) << 16 |
(unsigned long) *(p + 2) << 8 |
(unsigned long) *(p + 3) << 0;
}
 
 
void convertPartitionTable(PartEntry *e, int n) {
int i;
unsigned char *p;
 
for (i = 0; i < n; i++) {
p = (unsigned char *) &e[i];
e[i].type = getNumber(p + 0);
e[i].start = getNumber(p + 4);
e[i].size = getNumber(p + 8);
}
}
 
 
/**************************************************************/
 
 
int main(int argc, char *argv[]) {
char *diskName;
FILE *disk;
unsigned long diskSize;
unsigned long numSectors;
unsigned long partLast;
int i, j;
char c;
 
/* check command line arguments */
if (argc != 2) {
printf("Usage: %s <disk image file>\n", argv[0]);
exit(1);
}
diskName = argv[1];
/* determine disk size */
disk = fopen(diskName, "rb");
if (disk == NULL) {
error("cannot open disk image '%s'", diskName);
}
fseek(disk, 0, SEEK_END);
diskSize = ftell(disk);
numSectors = diskSize / SECTOR_SIZE;
fclose(disk);
printf("Disk '%s' has %lu (0x%lX) sectors.\n",
diskName, numSectors, numSectors);
if (numSectors < 32) {
error("disk is too small");
}
if (diskSize % SECTOR_SIZE != 0) {
printf("Warning: disk size is not a multiple of sector size!\n");
}
/* read partition table record */
disk = fopen(diskName, "rb");
if (disk == NULL) {
error("cannot open disk image '%s'", diskName);
}
fseek(disk, 1 * SECTOR_SIZE, SEEK_SET);
if (fread(ptr, 1, SECTOR_SIZE, disk) != SECTOR_SIZE) {
error("cannot read partition table from disk image '%s'", diskName);
}
fclose(disk);
convertPartitionTable(ptr, NPE);
/* show partition table */
printf("Partitions:\n");
printf(" # b type start last size description\n");
for (i = 0; i < NPE; i++) {
if (ptr[i].type != 0) {
partLast = ptr[i].start + ptr[i].size - 1;
} else {
partLast = 0;
}
printf("%2d %s 0x%08lX 0x%08lX 0x%08lX 0x%08lX ",
i,
ptr[i].type & 0x80000000 ? "*" : " ",
ptr[i].type & 0x7FFFFFFF,
ptr[i].start,
partLast,
ptr[i].size);
for (j = 0; j < DESCR_SIZE; j++) {
c = ptr[i].descr[j];
if (c == '\0') {
break;
}
if (c >= 0x20 && c < 0x7F) {
printf("%c", c);
} else {
printf(".");
}
}
printf("\n");
}
/* done */
return 0;
}
/disk/tools/shpart/Makefile
0,0 → 1,36
#
# Makefile for shpart utility
#
 
BUILD = ../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = shpart.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = shpart
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/tools/mkdisk/mkdisk.c
0,0 → 1,75
/*
* mkdisk.c -- make an empty physical disk
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
 
 
#define SECTOR_SIZE 512
#define MIN_NUMBER_SECTORS 100
#define SECTORS_PER_MB ((1 << 20) / SECTOR_SIZE)
#define DATA_BYTE 0xE5
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
 
 
void usage(void) {
fprintf(stderr, "Usage: mkdisk <file name> <n>[M]\n");
fprintf(stderr, " <n>: decimal number of sectors\n");
fprintf(stderr, " if 'M' appended: megabytes instead of sectors\n");
fprintf(stderr, " (sector size is always %d bytes)\n", SECTOR_SIZE);
exit(1);
}
 
 
int main(int argc, char *argv[]) {
FILE *dskFile;
int numSectors;
unsigned char sectorBuffer[SECTOR_SIZE];
int i;
 
if (argc != 3) {
usage();
}
numSectors = atoi(argv[2]);
i = strlen(argv[2]) - 1;
if (argv[2][i] == 'M') {
numSectors *= SECTORS_PER_MB;
}
if (numSectors < MIN_NUMBER_SECTORS) {
error("this disk is too small to be useful (minimum size is %d sectors)",
MIN_NUMBER_SECTORS);
}
dskFile = fopen(argv[1], "wb");
if (dskFile == NULL) {
error("cannot open file '%s' for write", argv[1]);
}
fprintf(stdout,
"Creating disk '%s' with %d sectors (around %d MB)...\n",
argv[1], numSectors,
(numSectors + SECTORS_PER_MB / 2) / SECTORS_PER_MB);
for (i = 0; i < SECTOR_SIZE; i++) {
sectorBuffer[i] = DATA_BYTE;
}
for (i = 0; i < numSectors; i++) {
if (fwrite(sectorBuffer, SECTOR_SIZE, 1, dskFile) != 1) {
error("write error on file '%s', sector %d", argv[1], i);
}
}
fclose(dskFile);
return 0;
}
/disk/tools/mkdisk/Makefile
0,0 → 1,36
#
# Makefile for disk creator
#
 
BUILD = ../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = mkdisk.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = mkdisk
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/tools/fs-NetBSD/Makefile.run
0,0 → 1,30
#
# Makefile for building a NetBSD disklabel and file system
#
 
BUILD = ../..
DISK = ../disk.img
 
all: proto-fs
$(BUILD)/bin/NetBSD-makefs -t ffs -B be -s 106496b \
-f 20000 -o version=1,bsize=8192,fsize=1024 \
fs.img ./root
dd if=fs.img of=$(DISK) bs=512 seek=81920 conv=notrunc
$(BUILD)/bin/NetBSD-wrboot ./bootblk $(DISK) 3
$(BUILD)/bin/NetBSD-dsklbl -wb $(DISK) 3
 
proto-fs:
mkdir -p ./root
cp ./loader ./root
cp $(BUILD)/../os-bin/NetBSD/* ./root
mkdir -p ./root/bin
mkdir -p ./root/dev
mkdir -p ./root/etc
mkdir -p ./root/tmp
mkdir -p ./root/usr
mkdir -p ./root/usr/data
cp $(BUILD)/data/* ./root/usr/data
 
clean:
rm -f *~ fs.img
rm -rf ./root
/disk/tools/fs-NetBSD/loader/disklabel.h
0,0 → 1,62
/*
* disklabel.h -- structure of the disklabel
*/
 
 
#ifndef _DISKLABEL_H_
#define _DISKLABEL_H_
 
 
#define DSKMAGIC 0x82564557
#define NTYPENAME 16
#define NPACKNAME 16
#define NDDATA 5
#define NSPARE 5
#define MAXPARTS 16
#define PADSIZE 108
 
 
typedef struct {
uint32_t p_size; /* number of sectors in partition */
uint32_t p_offset; /* starting sector */
uint32_t p_fsize; /* filesystem basic fragment size */
uint8_t p_fstype; /* filesystem type */
uint8_t p_frag; /* filesystem fragments per block */
uint16_t p_cpg; /* filesystem cylinders per group */
} Partition;
 
typedef struct {
uint32_t d_magic; /* magic number */
uint16_t d_type; /* drive type */
uint16_t d_subtype; /* controller, d_type specific */
char d_typename[NTYPENAME]; /* type name */
char d_packname[NPACKNAME]; /* pack identifier */
uint32_t d_secsize; /* bytes per sector */
uint32_t d_nsectors; /* data sectors per track */
uint32_t d_ntracks; /* tracks per cylinder */
uint32_t d_ncylinders; /* data cylinders per unit */
uint32_t d_secpercyl; /* data sectors per cylinder */
uint32_t d_secperunit; /* data sectors per unit */
uint16_t d_sparespertrack; /* spare sectors per track */
uint16_t d_sparespercyl; /* spare sectors per cylinder */
uint32_t d_acylinders; /* alternative cylinders per unit */
uint16_t d_rpm; /* rotational speed */
uint16_t d_interleave; /* hardware sector interleave */
uint16_t d_trackskew; /* sector 0 skew, per track */
uint16_t d_cylskew; /* sector 0 skew, per cylinder */
uint32_t d_headswitch; /* head switch time, usec */
uint32_t d_trkseek; /* track-to-track seek, usec */
uint32_t d_flags; /* generic flags */
uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
uint32_t d_spare[NSPARE]; /* reserved for future use */
uint32_t d_magic2; /* the magic number again */
uint16_t d_checksum; /* xor of data incl partitions */
uint16_t d_npartitions; /* number of partitions */
uint32_t d_bbsize; /* size of boot area at sector 0, bytes */
uint32_t d_sbsize; /* size of filesystem superblock, bytes */
Partition d_parts[MAXPARTS]; /* the partition table */
uint8_t d_pad[PADSIZE]; /* pad up to sector size */
} DiskLabel;
 
 
#endif /* _DISKLABEL_H_ */
/disk/tools/fs-NetBSD/loader/biolib.h
0,0 → 1,15
/*
* biolib.h -- basic I/O library
*/
 
 
#ifndef _BIOLIB_H_
#define _BIOLIB_H_
 
 
char getc(void);
void putc(char c);
int rwscts(int dskno, int cmd, int sector, int addr, int count);
 
 
#endif /* _BIOLIB_H_ */
/disk/tools/fs-NetBSD/loader/loader.c
0,0 → 1,511
/*
* loader.c -- the NetBSD system loader
*/
 
 
#include "types.h"
#include "disklabel.h"
#include "fs.h"
#include "dinode.h"
#include "dir.h"
#include "stdarg.h"
#include "auxlib.h"
#include "biolib.h"
#include "elf.h"
 
 
/**************************************************************/
 
/* constants and data types */
 
 
#define DFLT_KERNEL "/netbsd" /* default path to kernel */
 
#define MAX_LINE 100 /* line buffer size */
 
#define SSHIFT 9 /* ld of sector size */
#define SSIZE (1 << SSHIFT) /* disk sector size in bytes */
#define SMASK (SSIZE - 1) /* sector mask */
 
#define BSHIFT 13 /* ld of block size */
#define BSIZE (1 << BSHIFT) /* disk block size in bytes */
#define BMASK (BSIZE - 1) /* block mask */
 
 
typedef struct ufs1_dinode Dinode;
typedef struct direct Dirent;
typedef unsigned int daddr_t;
typedef unsigned int ino_t;
 
 
#define NIPB (BSIZE / sizeof(Dinode))
 
#define NULL 0
 
 
/**************************************************************/
 
/* debugging */
 
 
Bool debugReadSectors = FALSE;
Bool debugReadDiskLabel = FALSE;
Bool debugReadSuperBlock = FALSE;
Bool debugGetInode = FALSE;
Bool debugSearchDir = FALSE;
Bool debugLoadElf = FALSE;
 
 
/**************************************************************/
 
/* halt with error message */
 
 
void halt(char *msg) {
printf("%s, machine halted.\n", msg);
while (1) ;
}
 
 
/**************************************************************/
 
/* disk I/O */
 
 
unsigned int bootDisk = 0; /* gets loaded by previous stage */
/* never changed */
unsigned int startSector = 0; /* gets loaded by previous stage */
/* initially holds start of slice */
/* disklabel read --> start of partition */
unsigned int numSectors = 0; /* gets loaded by previous stage */
/* initially holds size of slice */
/* disklabel read --> size of partition */
 
unsigned int spf; /* superblock read --> sectors per fragment */
unsigned int spb; /* superblock read --> sectors per block */
 
 
/*
* read disk sectors
*
* NOTE: buffer must be word-aligned
*/
void readSectors(unsigned int start,
unsigned int count,
void *buffer) {
unsigned int sector;
int result;
 
if (start + count > numSectors) {
halt("Sector number exceeds slice or partition size");
}
sector = startSector + start;
if (debugReadSectors) {
printf("DEBUG: reading sector 0x%08X, %d sectors\n", sector, count);
}
result = rwscts(bootDisk, 'r', sector,
(unsigned int) buffer & 0x3FFFFFFF, count);
if (result != 0) {
halt("Load error");
}
}
 
 
/**************************************************************/
 
/* disklabel handling */
 
 
unsigned int diskLabel[SSIZE / sizeof(unsigned int)];
DiskLabel *dlp = (DiskLabel *) &diskLabel[0];
 
unsigned int superStart; /* partition-relative offset, in sectors */
unsigned int superSize; /* size, in sectors */
 
 
void readDiskLabel(void) {
readSectors(1, 1, dlp);
if (dlp->d_magic != DSKMAGIC ||
dlp->d_magic2 != DSKMAGIC) {
halt("Disklabel corrupted");
}
 
startSector = dlp->d_parts[0].p_offset;
numSectors = dlp->d_parts[0].p_size;
 
superStart = dlp->d_bbsize;
if ((superStart & SMASK) != 0) {
halt("Superblock offset is not multiple of sector size");
}
superStart >>= SSHIFT;
 
superSize = dlp->d_sbsize;
if ((superSize & SMASK) != 0) {
halt("Superblock size is not multiple of sector size");
}
if (superSize > BSIZE) {
halt("Superblock too big");
}
superSize >>= SSHIFT;
 
if (debugReadDiskLabel) {
printf("DEBUG: super start = %d sectors, super size = %d sectors\n",
superStart, superSize);
}
}
 
 
/**************************************************************/
 
/* superblock handling */
 
 
unsigned int superBlock[BSIZE / sizeof(unsigned int)];
struct fs *sbp = (struct fs *) &superBlock[0];
 
 
void readSuperBlock(void) {
readSectors(superStart, superSize, sbp);
if (sbp->fs_magic != FS_UFS1_MAGIC) {
halt("Wrong magic number in superblock");
}
spf = sbp->fs_fsize / SSIZE;
spb = sbp->fs_bsize / SSIZE;
if (sbp->fs_inopb != NIPB) {
halt("Wrong number of inodes per block");
}
if (debugReadSuperBlock) {
printf("DEBUG: %d sectors per fragment\n", spf);
printf("DEBUG: %d sectors per block\n", spb);
printf("DEBUG: %d inodes per block\n", NIPB);
}
}
 
 
/**************************************************************/
 
/* file operations */
 
 
unsigned int sibno = 0;
unsigned int sib[8192 / sizeof(unsigned int)];
unsigned int *sibp = (unsigned int *) &sib[0];
 
 
/*
* read a block of a file
*
* NOTE: addr must be word-aligned
*/
void readFileBlock(Dinode *ip, int blkno, void *addr) {
unsigned int diskFrag;
 
if (blkno < NDADDR) {
/* direct block */
diskFrag = ip->di_db[blkno];
} else
if (blkno - NDADDR < sbp->fs_bsize / sizeof(int32_t)) {
/* single indirect block */
if (sibno != ip->di_ib[0]) {
sibno = ip->di_ib[0];
readSectors(sibno * spf, spb, sibp);
}
diskFrag = sibp[blkno - NDADDR];
} else {
/* double or triple indirect blocks */
halt("Cannot do double or triple indirect blocks");
}
readSectors(diskFrag * spf, spb, addr);
}
 
 
/*
* read a number of bytes from a file
*/
void readFile(Dinode *ip, unsigned int offset,
unsigned int size, void *buffer) {
unsigned int dskblk[8192 / sizeof(unsigned int)];
unsigned char *bufp;
unsigned char *blkp;
unsigned int blkno;
unsigned int index;
unsigned int aux;
unsigned int numBytes;
int i;
 
bufp = (unsigned char *) buffer;
blkp = (unsigned char *) dskblk;
blkno = offset / sbp->fs_bsize;
index = offset % sbp->fs_bsize;
aux = sbp->fs_bsize - index;
numBytes = (size <= aux) ? size : aux;
readFileBlock(ip, blkno, blkp);
for (i = 0; i < numBytes; i++) {
*bufp++ = blkp[index++];
}
blkno++;
size -= numBytes;
while (size >= sbp->fs_bsize) {
index = 0;
numBytes = sbp->fs_bsize;
readFileBlock(ip, blkno, blkp);
for (i = 0; i < numBytes; i++) {
*bufp++ = blkp[index++];
}
blkno++;
size -= numBytes;
}
if (size > 0) {
index = 0;
numBytes = size;
readFileBlock(ip, blkno, blkp);
for (i = 0; i < numBytes; i++) {
*bufp++ = blkp[index++];
}
}
}
 
 
/**************************************************************/
 
/* inode handling */
 
 
unsigned int inodeBlock[BSIZE / sizeof(unsigned int)];
Dinode *ibp = (Dinode *) &inodeBlock[0];
 
 
Dinode *getInode(unsigned int inode) {
unsigned int fnum;
unsigned int inum;
Dinode *ip;
 
fnum = ino_to_fsba(sbp, inode);
inum = ino_to_fsbo(sbp, inode);
if (debugGetInode) {
printf("DEBUG: getting inode 0x%08X\n", inode);
printf("DEBUG: this is in fragment %d, inode %d\n", fnum, inum);
}
readSectors(fnum * spf, spb, ibp);
ip = ibp + inum;
if (ip->di_size[0] != 0) {
halt("File too big");
}
if (debugGetInode) {
printf("DEBUG: mode of file = 0x%04X\n", ip->di_mode);
printf("DEBUG: size of file = 0x%08X\n", ip->di_size[1]);
}
return ip;
}
 
 
/**************************************************************/
 
/* convert path to inode */
 
 
unsigned int directoryBlock[BSIZE / sizeof(unsigned int)];
Dirent *dbp = (Dirent *) &directoryBlock[0];
 
 
Dinode *pathToInode(char *path) {
Dinode *ip;
char c;
char dirBuffer[FFS_MAXNAMLEN];
char *cp;
unsigned int offset;
Dirent *dp;
unsigned int ino;
unsigned int len;
 
/* get root inode */
ip = getInode(ROOTINO);
/* traverse file system tree while matching path components */
c = *path++;
while (1) {
/* skip leading slashes in path component */
while (c == '/') {
c = *path++;
}
if (c == '\0') {
/* no more path components */
break;
}
/* if there is another component, gather up its name */
cp = dirBuffer;
while (c != '/' && c != '\0') {
if (cp < &dirBuffer[FFS_MAXNAMLEN]) {
*cp++ = c;
}
c = *path++;
}
*cp++ = '\0';
/* ip must be a directory */
if ((ip->di_mode & IFMT) != IFDIR) {
return NULL;
}
if (debugSearchDir) {
printf("DEBUG: this is a directory, ok\n");
printf("DEBUG: path component to search for = '%s'\n", dirBuffer);
}
/* search directory */
offset = 0;
while (1) {
if (offset >= ip->di_size[1]) {
/* component not found */
return NULL;
}
if ((offset & BMASK) == 0) {
/* read the next directory block */
readFileBlock(ip, offset >> BSHIFT, dbp);
dp = dbp;
}
ino = dp->d_fileno;
len = dp->d_reclen;
if (debugSearchDir) {
printf("DEBUG: ino = %4d, len = %4d, ", ino, len);
printf("dirsiz = %4d, name = %s\n", DIRSIZ(0, dp, 0), dp->d_name);
}
if (ino != 0) {
if (strcmp(dirBuffer, dp->d_name) == 0) {
/* component found */
break;
}
}
/* no match, try next entry */
dp = (Dirent *) ((unsigned char *) dp + len);
offset += len;
}
/* get corresponding inode */
ip = getInode(ino);
/* look for more components */
}
return ip;
}
 
 
/**************************************************************/
 
/* load an ELF executable */
 
 
#define MAX_PHDR_SIZE 100
 
 
Bool loadElf(Dinode *ip, unsigned int *entryPointPtr) {
Elf32_Ehdr fileHeader;
Elf32_Addr entry;
Elf32_Off phoff;
Elf32_Half phentsize;
Elf32_Half phnum;
int i;
unsigned int phdrBuf[MAX_PHDR_SIZE / sizeof(unsigned int)];
Elf32_Phdr *phdrPtr;
Elf32_Word ptype;
Elf32_Off offset;
Elf32_Addr address;
Elf32_Word filesize;
Elf32_Word memsize;
Elf32_Word flags;
Elf32_Word align;
unsigned char *memPtr;
int j;
 
readFile(ip, 0, sizeof(Elf32_Ehdr), &fileHeader);
if (fileHeader.e_ident[EI_MAG0] != ELFMAG0 ||
fileHeader.e_ident[EI_MAG1] != ELFMAG1 ||
fileHeader.e_ident[EI_MAG2] != ELFMAG2 ||
fileHeader.e_ident[EI_MAG3] != ELFMAG3 ||
fileHeader.e_ident[EI_CLASS] != ELFCLASS32 ||
fileHeader.e_ident[EI_DATA] != ELFDATA2MSB ||
fileHeader.e_type != ET_EXEC ||
fileHeader.e_machine != EM_ECO32) {
/* file is not in ECO32-ELF executable format */
return FALSE;
}
entry = fileHeader.e_entry;
phoff = fileHeader.e_phoff;
phentsize = fileHeader.e_phentsize;
phnum = fileHeader.e_phnum;
if (debugLoadElf) {
printf("DEBUG: entry point (virtual addr) : 0x%08X\n", entry);
printf("DEBUG: program header table at : %d\n", phoff);
printf("DEBUG: prog hdr tbl entry size : %d\n", phentsize);
printf("DEBUG: num prog hdr tbl entries : %d\n", phnum);
}
for (i = 0 ; i < phnum; i++) {
printf("Processing program header %d\n", i);
readFile(ip, phoff + i * phentsize, phentsize, phdrBuf);
phdrPtr = (Elf32_Phdr *) phdrBuf;
ptype = phdrPtr->p_type;
if (ptype != PT_LOAD) {
printf(" type is %u, ignored\n", ptype);
continue;
}
offset = phdrPtr->p_offset;
address = phdrPtr->p_vaddr;
filesize = phdrPtr->p_filesz;
memsize = phdrPtr->p_memsz;
flags = phdrPtr->p_flags;
align = phdrPtr->p_align;
if (debugLoadElf) {
printf("DEBUG: offset : 0x%08X bytes\n", offset);
printf("DEBUG: address : 0x%08X\n", address);
printf("DEBUG: filesize : 0x%08X bytes\n", filesize);
printf("DEBUG: memsize : 0x%08X bytes\n", memsize);
printf("DEBUG: flags : 0x%08X\n", flags);
printf("DEBUG: align : 0x%08X\n", align);
}
memPtr = (unsigned char *) address;
readFile(ip, offset, filesize, memPtr);
for (j = filesize; j < memsize; j++) {
memPtr[j] = 0;
}
printf(" segment of %u bytes read", filesize);
printf(" (+ %u bytes zeroed)", memsize - filesize);
printf(", vaddr = 0x%08X\n", address);
}
*entryPointPtr = entry;
return TRUE;
}
 
 
/**************************************************************/
 
/* main program */
 
 
unsigned int entryPoint; /* where to continue from main() */
 
 
int main(void) {
char line[MAX_LINE];
Dinode *ip;
 
printf("\n");
printf("NetBSD system loader\n");
readDiskLabel();
readSuperBlock();
strcpy(line, DFLT_KERNEL);
while (1) {
getLine("\nPlease enter path to kernel: ", line, MAX_LINE);
ip = pathToInode(line);
if (ip == NULL) {
printf("'%s' not found\n", line);
continue;
}
if ((ip->di_mode & IFMT) != IFREG) {
printf("'%s' is not a regular file\n", line);
continue;
}
printf("Loading '%s'...\n", line);
if (!loadElf(ip, &entryPoint)) {
printf("'%s' cannot be loaded\n", line);
continue;
}
/* kernel successfully loaded */
break;
}
printf("Starting '%s' at address 0x%08X...\n", line, entryPoint);
return 0;
}
/disk/tools/fs-NetBSD/loader/dinode.h
0,0 → 1,180
/* $NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp $ */
 
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dinode.h 8.9 (Berkeley) 3/29/95
*/
 
/*
* NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
*/
 
#ifndef _UFS_UFS_DINODE_H_
#define _UFS_UFS_DINODE_H_
 
/*
* The root inode is the root of the file system. Inode 0 can't be used for
* normal purposes and historically bad blocks were linked to inode 1, thus
* the root inode is 2. (Inode 1 is no longer used for this purpose, however
* numerous dump tapes make this assumption, so we are stuck with it).
*/
#define ROOTINO ((ino_t)2)
 
/*
* The Whiteout inode# is a dummy non-zero inode number which will
* never be allocated to a real file. It is used as a place holder
* in the directory entry which has been tagged as a DT_W entry.
* See the comments about ROOTINO above.
*/
#define WINO ((ino_t)1)
 
/*
* A dinode contains all the meta-data associated with a UFS file.
* This structure defines the on-disk format of a dinode. Since
* this structure describes an on-disk structure, all its fields
* are defined by types with precise widths.
*/
 
#define NXADDR 2
#define NDADDR 12 /* Direct addresses in inode. */
#define NIADDR 3 /* Indirect addresses in inode. */
 
struct ufs1_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
union {
u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */
u_int32_t inumber; /* 4: Lfs: inode number. */
} di_u;
u_int64_t di_size; /* 8: File byte count. */
int32_t di_atime; /* 16: Last access time. */
int32_t di_atimensec; /* 20: Last access time. */
int32_t di_mtime; /* 24: Last modified time. */
int32_t di_mtimensec; /* 28: Last modified time. */
int32_t di_ctime; /* 32: Last inode change time. */
int32_t di_ctimensec; /* 36: Last inode change time. */
int32_t di_db[NDADDR]; /* 40: Direct disk blocks. */
int32_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
u_int32_t di_flags; /* 100: Status flags (chflags). */
u_int32_t di_blocks; /* 104: Blocks actually held. */
int32_t di_gen; /* 108: Generation number. */
u_int32_t di_uid; /* 112: File owner. */
u_int32_t di_gid; /* 116: File group. */
u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */
};
 
struct ufs2_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
u_int32_t di_uid; /* 4: File owner. */
u_int32_t di_gid; /* 8: File group. */
u_int32_t di_blksize; /* 12: Inode blocksize. */
u_int64_t di_size; /* 16: File byte count. */
u_int64_t di_blocks; /* 24: Bytes actually held. */
int64_t di_atime; /* 32: Last access time. */
int64_t di_mtime; /* 40: Last modified time. */
int64_t di_ctime; /* 48: Last inode change time. */
int64_t di_birthtime; /* 56: Inode creation time. */
int32_t di_mtimensec; /* 64: Last modified time. */
int32_t di_atimensec; /* 68: Last access time. */
int32_t di_ctimensec; /* 72: Last inode change time. */
int32_t di_birthnsec; /* 76: Inode creation time. */
int32_t di_gen; /* 80: Generation number. */
u_int32_t di_kernflags; /* 84: Kernel flags. */
u_int32_t di_flags; /* 88: Status flags (chflags). */
int32_t di_extsize; /* 92: External attributes block. */
int64_t di_extb[NXADDR];/* 96: External attributes block. */
int64_t di_db[NDADDR]; /* 112: Direct disk blocks. */
int64_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */
int64_t di_spare[2]; /* 240: Reserved; currently unused */
};
 
/*
* The di_db fields may be overlaid with other information for
* file types that do not have associated disk storage. Block
* and character devices overlay the first data block with their
* dev_t value. Short symbolic links place their path in the
* di_db area.
*/
#define di_inumber di_u.inumber
#define di_ogid di_u.oldids[1]
#define di_ouid di_u.oldids[0]
#define di_rdev di_db[0]
#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(int32_t))
#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(int64_t))
 
#define MAXSYMLINKLEN(ip) \
((ip)->i_ump->um_fstype == UFS1) ? \
MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2
 
/* NeXT used to keep short symlinks in the inode even when using
* FS_42INODEFMT. In that case fs->fs_maxsymlinklen is probably -1,
* but short symlinks were stored in inodes shorter than this:
*/
#define APPLEUFS_MAXSYMLINKLEN 60
 
/* File permissions. */
#define IEXEC 0000100 /* Executable. */
#define IWRITE 0000200 /* Writable. */
#define IREAD 0000400 /* Readable. */
#define ISVTX 0001000 /* Sticky bit. */
#define ISGID 0002000 /* Set-gid. */
#define ISUID 0004000 /* Set-uid. */
 
/* File types. */
#define IFMT 0170000 /* Mask of file type. */
#define IFIFO 0010000 /* Named pipe (fifo). */
#define IFCHR 0020000 /* Character device. */
#define IFDIR 0040000 /* Directory file. */
#define IFBLK 0060000 /* Block device. */
#define IFREG 0100000 /* Regular file. */
#define IFLNK 0120000 /* Symbolic link. */
#define IFSOCK 0140000 /* UNIX domain socket. */
#define IFWHT 0160000 /* Whiteout. */
 
/* Size of the on-disk inode. */
#define DINODE1_SIZE (sizeof(struct ufs1_dinode)) /* 128 */
#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
 
#endif /* !_UFS_UFS_DINODE_H_ */
/disk/tools/fs-NetBSD/loader/types.h
0,0 → 1,38
/*
* types.h -- additional types
*/
 
 
#ifndef _TYPES_H_
#define _TYPES_H_
 
 
typedef unsigned int uint64_t[2];
typedef unsigned int u_int64_t[2];
 
typedef unsigned int uint32_t;
typedef unsigned int u_int32_t;
 
typedef unsigned short uint16_t;
typedef unsigned short u_int16_t;
 
typedef unsigned char uint8_t;
typedef unsigned char u_int8_t;
typedef unsigned char u_char;
 
typedef unsigned int int64_t[2];
 
typedef int int32_t;
 
typedef short int16_t;
 
typedef char int8_t;
 
 
typedef int Bool;
 
#define FALSE 0
#define TRUE 1
 
 
#endif /* _TYPES_H_ */
/disk/tools/fs-NetBSD/loader/elf.h
0,0 → 1,131
/*
* elf.h -- structure of ELF files
*/
 
 
#ifndef _ELF_H_
#define _ELF_H_
 
 
typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
typedef signed int Elf32_Sword;
typedef unsigned int Elf32_Word;
 
 
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
#define EI_NIDENT 16
 
#define ELFMAG0 0x7F
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
 
#define ELFCLASSNONE 0
#define ELFCLASS32 1
#define ELFCLASS64 2
 
#define ELFDATANONE 0
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
 
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
#define ET_CORE 4
 
#define EM_NONE 0
#define EM_M32 1
#define EM_SPARC 2
#define EM_386 3
#define EM_68K 4
#define EM_88K 5
#define EM_860 7
#define EM_MIPS 8
#define EM_ECO32 0xEC05
 
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
 
 
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7FFFFFFF
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xFFFFFFFF
 
#define SHF_WRITE 0x00000001
#define SHF_ALLOC 0x00000002
#define SHF_EXECINSTR 0x00000004
#define SHF_MASKPROC 0xF0000000
 
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
 
 
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_TLS 7
 
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
 
 
#endif /* _ELF_H_ */
/disk/tools/fs-NetBSD/loader/README
0,0 → 1,10
 
Basic Tasks For The System Loader
---------------------------------
 
1) Interactively accept a path to an operating system kernel executable.
2) Traverse the file system from root to the kernel executable.
3) Read the kernel executable (possibly with indirect blocks).
4) Interpret the file format (ELF) while reading the kernel.
5) Start the loaded kernel (possibly with arguments).
 
/disk/tools/fs-NetBSD/loader/fs.h
0,0 → 1,752
/* $NetBSD: fs.h,v 1.56 2011/03/06 17:08:38 bouyer Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fs.h 8.13 (Berkeley) 3/21/95
*/
 
/*
* NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
*/
 
#ifndef _UFS_FFS_FS_H_
#define _UFS_FFS_FS_H_
 
/*
* Each disk drive contains some number of file systems.
* A file system consists of a number of cylinder groups.
* Each cylinder group has inodes and data.
*
* A file system is described by its super-block, which in turn
* describes the cylinder groups. The super-block is critical
* data and is replicated in each cylinder group to protect against
* catastrophic loss. This is done at `newfs' time and the critical
* super-block data does not change, so the copies need not be
* referenced further unless disaster strikes.
*
* For file system fs, the offsets of the various blocks of interest
* are given in the super block as:
* [fs->fs_sblkno] Super-block
* [fs->fs_cblkno] Cylinder group block
* [fs->fs_iblkno] Inode blocks
* [fs->fs_dblkno] Data blocks
* The beginning of cylinder group cg in fs, is given by
* the ``cgbase(fs, cg)'' macro.
*
* Depending on the architecture and the media, the superblock may
* reside in any one of four places. For tiny media where every block
* counts, it is placed at the very front of the partition. Historically,
* UFS1 placed it 8K from the front to leave room for the disk label and
* a small bootstrap. For UFS2 it got moved to 64K from the front to leave
* room for the disk label and a bigger bootstrap, and for really piggy
* systems we check at 256K from the front if the first three fail. In
* all cases the size of the superblock will be SBLOCKSIZE. All values are
* given in byte-offset form, so they do not imply a sector size. The
* SBLOCKSEARCH specifies the order in which the locations should be searched.
*
* Unfortunately the UFS2/FFSv2 change was done without adequate consideration
* of backward compatibility. In particular 'newfs' for a FFSv2 partition
* must overwrite any old FFSv1 superblock at 8k, and preferrably as many
* of the alternates as it can find - otherwise attempting to mount on a
* system that only supports FFSv1 is likely to succeed!.
* For a small FFSv1 filesystem, an old FFSv2 superblock can be left on
* the disk, and a system that tries to find an FFSv2 filesystem in preference
* to and FFSv1 one (as NetBSD does) can mount the old FFSv2 filesystem.
* As a added bonus, the 'first alternate' superblock of a FFSv1 filesystem
* with 64k blocks is at 64k - just where the code looks first when playing
* 'hunt the superblock'.
*
* The ffsv2 superblock layout (which might contain an ffsv1 filesystem)
* can be detected by checking for sb->fs_old_flags & FS_FLAGS_UPDATED.
* This is the default superblock type for NetBSD since ffsv2 support was added.
*/
#define BBSIZE 8192
#define BBOFF ((off_t)(0))
#define BBLOCK ((daddr_t)(0))
 
#define SBLOCK_FLOPPY 0
#define SBLOCK_UFS1 8192
#define SBLOCK_UFS2 65536
#define SBLOCK_PIGGY 262144
#define SBLOCKSIZE 8192
/*
* NB: Do not, under any circumstances, look for an ffsv1 filesystem at
* SBLOCK_UFS2. Doing so will find the wrong superblock for filesystems
* with a 64k block size.
*/
#define SBLOCKSEARCH \
{ SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
 
/*
* Max number of fragments per block. This value is NOT tweakable.
*/
#define MAXFRAG 8
 
 
 
/*
* Addresses stored in inodes are capable of addressing fragments
* of `blocks'. File system blocks of at most size MAXBSIZE can
* be optionally broken into 2, 4, or 8 pieces, each of which is
* addressable; these pieces may be DEV_BSIZE, or some multiple of
* a DEV_BSIZE unit.
*
* Large files consist of exclusively large data blocks. To avoid
* undue wasted disk space, the last data block of a small file may be
* allocated as only as many fragments of a large block as are
* necessary. The file system format retains only a single pointer
* to such a fragment, which is a piece of a single large block that
* has been divided. The size of such a fragment is determinable from
* information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
*
* The file system records space availability at the fragment level;
* to determine block availability, aligned fragments are examined.
*/
 
/*
* MINBSIZE is the smallest allowable block size.
* In order to insure that it is possible to create files of size
* 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
* MINBSIZE must be big enough to hold a cylinder group block,
* thus changes to (struct cg) must keep its size within MINBSIZE.
* Note that super blocks are always of size SBSIZE,
* and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
*/
#define MINBSIZE 4096
 
/*
* The path name on which the file system is mounted is maintained
* in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
* the super block for this name.
*/
#define MAXMNTLEN 468
 
/*
* The volume name for this filesystem is maintained in fs_volname.
* MAXVOLLEN defines the length of the buffer allocated.
* This space used to be part of of fs_fsmnt.
*/
#define MAXVOLLEN 32
 
/*
* There is a 128-byte region in the superblock reserved for in-core
* pointers to summary information. Originally this included an array
* of pointers to blocks of struct csum; now there are just four
* pointers and the remaining space is padded with fs_ocsp[].
* NOCSPTRS determines the size of this padding. One pointer (fs_csp)
* is taken away to point to a contiguous array of struct csum for
* all cylinder groups; a second (fs_maxcluster) points to an array
* of cluster sizes that is computed as cylinder groups are inspected;
* the third (fs_contigdirs) points to an array that tracks the
* creation of new directories; and the fourth (fs_active) is used
* by snapshots.
*/
#define NOCSPTRS ((128 / sizeof(void *)) - 4)
 
/*
* A summary of contiguous blocks of various sizes is maintained
* in each cylinder group. Normally this is set by the initial
* value of fs_maxcontig. To conserve space, a maximum summary size
* is set by FS_MAXCONTIG.
*/
#define FS_MAXCONTIG 16
 
/*
* The maximum number of snapshot nodes that can be associated
* with each filesystem. This limit affects only the number of
* snapshot files that can be recorded within the superblock so
* that they can be found when the filesystem is mounted. However,
* maintaining too many will slow the filesystem performance, so
* having this limit is a good idea.
*/
#define FSMAXSNAP 20
 
/*
* Used to identify special blocks in snapshots:
*
* BLK_NOCOPY - A block that was unallocated at the time the snapshot
* was taken, hence does not need to be copied when written.
* BLK_SNAP - A block held by another snapshot that is not needed by this
* snapshot. When the other snapshot is freed, the BLK_SNAP entries
* are converted to BLK_NOCOPY. These are needed to allow fsck to
* identify blocks that are in use by other snapshots (which are
* expunged from this snapshot).
*/
#define BLK_NOCOPY ((daddr_t)(1))
#define BLK_SNAP ((daddr_t)(2))
 
/*
* MINFREE gives the minimum acceptable percentage of file system
* blocks which may be free. If the freelist drops below this level
* only the superuser may continue to allocate blocks. This may
* be set to 0 if no reserve of free blocks is deemed necessary,
* however throughput drops by fifty percent if the file system
* is run at between 95% and 100% full; thus the minimum default
* value of fs_minfree is 5%. However, to get good clustering
* performance, 10% is a better choice. This value is used only
* when creating a file system and can be overriden from the
* command line. By default we choose to optimize for time.
*/
#define MINFREE 5
#define DEFAULTOPT FS_OPTTIME
 
/*
* Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
* tune the layout preferences for directories within a filesystem.
* His algorithm can be tuned by adjusting the following parameters
* which tell the system the average file size and the average number
* of files per directory. These defaults are well selected for typical
* filesystems, but may need to be tuned for odd cases like filesystems
* being used for squid caches or news spools.
*/
#define AVFILESIZ 16384 /* expected average file size */
#define AFPDIR 64 /* expected number of files per directory */
 
/*
* Per cylinder group information; summarized in blocks allocated
* from first cylinder group data blocks. These blocks have to be
* read in from fs_csaddr (size fs_cssize) in addition to the
* super block.
*/
struct csum {
int32_t cs_ndir; /* number of directories */
int32_t cs_nbfree; /* number of free blocks */
int32_t cs_nifree; /* number of free inodes */
int32_t cs_nffree; /* number of free frags */
};
 
struct csum_total {
int64_t cs_ndir; /* number of directories */
int64_t cs_nbfree; /* number of free blocks */
int64_t cs_nifree; /* number of free inodes */
int64_t cs_nffree; /* number of free frags */
int64_t cs_spare[4]; /* future expansion */
};
 
 
/*
* Super block for an FFS file system in memory.
*/
struct fs {
int32_t fs_firstfield; /* historic file system linked list, */
int32_t fs_unused_1; /* used for incore super blocks */
int32_t fs_sblkno; /* addr of super-block in filesys */
int32_t fs_cblkno; /* offset of cyl-block in filesys */
int32_t fs_iblkno; /* offset of inode-blocks in filesys */
int32_t fs_dblkno; /* offset of first data after cg */
int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */
int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */
int32_t fs_old_time; /* last time written */
int32_t fs_old_size; /* number of blocks in fs */
int32_t fs_old_dsize; /* number of data blocks in fs */
int32_t fs_ncg; /* number of cylinder groups */
int32_t fs_bsize; /* size of basic blocks in fs */
int32_t fs_fsize; /* size of frag blocks in fs */
int32_t fs_frag; /* number of frags in a block in fs */
/* these are configuration parameters */
int32_t fs_minfree; /* minimum percentage of free blocks */
int32_t fs_old_rotdelay; /* num of ms for optimal next block */
int32_t fs_old_rps; /* disk revolutions per second */
/* these fields can be computed from the others */
int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
int32_t fs_fshift; /* ``numfrags'' calc number of frags */
/* these are configuration parameters */
int32_t fs_maxcontig; /* max number of contiguous blks */
int32_t fs_maxbpg; /* max number of blks per cyl group */
/* these fields can be computed from the others */
int32_t fs_fragshift; /* block to frag shift */
int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t fs_sbsize; /* actual size of super block */
int32_t fs_spare1[2]; /* old fs_csmask */
/* old fs_csshift */
int32_t fs_nindir; /* value of NINDIR */
int32_t fs_inopb; /* value of INOPB */
int32_t fs_old_nspf; /* value of NSPF */
/* yet another configuration parameter */
int32_t fs_optim; /* optimization preference, see below */
/* these fields are derived from the hardware */
int32_t fs_old_npsect; /* # sectors/track including spares */
int32_t fs_old_interleave; /* hardware sector interleave */
int32_t fs_old_trackskew; /* sector 0 skew, per track */
/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
int32_t fs_id[2]; /* unique file system id */
/* sizes determined by number of cylinder groups and their sizes */
int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */
int32_t fs_cssize; /* size of cyl grp summary area */
int32_t fs_cgsize; /* cylinder group size */
/* these fields are derived from the hardware */
int32_t fs_spare2; /* old fs_ntrak */
int32_t fs_old_nsect; /* sectors per track */
int32_t fs_old_spc; /* sectors per cylinder */
int32_t fs_old_ncyl; /* cylinders in file system */
int32_t fs_old_cpg; /* cylinders per group */
int32_t fs_ipg; /* inodes per group */
int32_t fs_fpg; /* blocks per group * fs_frag */
/* this data must be re-computed after crashes */
struct csum fs_old_cstotal; /* cylinder summary information */
/* these fields are cleared at mount time */
int8_t fs_fmod; /* super block modified flag */
uint8_t fs_clean; /* file system is clean flag */
int8_t fs_ronly; /* mounted read-only flag */
uint8_t fs_old_flags; /* see FS_ flags below */
u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
u_char fs_volname[MAXVOLLEN]; /* volume name */
uint64_t fs_swuid; /* system-wide uid */
int32_t fs_pad;
/* these fields retain the current block allocation info */
int32_t fs_cgrotor; /* last cg searched (UNUSED) */
void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
u_int8_t *fs_contigdirs; /* # of contiguously allocated dirs */
struct csum *fs_csp; /* cg summary info buffer for fs_cs */
int32_t *fs_maxcluster; /* max cluster in each cyl group */
u_char *fs_active; /* used by snapshots to track fs */
int32_t fs_old_cpc; /* cyl per cycle in postbl */
/* this area is otherwise allocated unless fs_old_flags & FS_FLAGS_UPDATED */
int32_t fs_maxbsize; /* maximum blocking factor permitted */
uint8_t fs_journal_version; /* journal format version */
uint8_t fs_journal_location; /* journal location type */
uint8_t fs_journal_reserved[2];/* reserved for future use */
uint32_t fs_journal_flags; /* journal flags */
uint64_t fs_journallocs[4]; /* location info for journal */
uint32_t fs_quota_magic; /* see quota2.h */
uint8_t fs_quota_flags; /* see quota2.h */
uint8_t fs_quota_reserved[3];
uint64_t fs_quotafile[2]; /* pointer to quota inodes */
int64_t fs_sparecon64[9]; /* reserved for future use */
int64_t fs_sblockloc; /* byte offset of standard superblock */
struct csum_total fs_cstotal; /* cylinder summary information */
int64_t fs_time; /* last time written */
int64_t fs_size; /* number of blocks in fs */
int64_t fs_dsize; /* number of data blocks in fs */
int64_t fs_csaddr; /* blk addr of cyl grp summary area */
int64_t fs_pendingblocks; /* blocks in process of being freed */
int32_t fs_pendinginodes; /* inodes in process of being freed */
int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
/* back to stuff that has been around a while */
int32_t fs_avgfilesize; /* expected average file size */
int32_t fs_avgfpdir; /* expected # of files per directory */
int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
int32_t fs_sparecon32[26]; /* reserved for future constants */
uint32_t fs_flags; /* see FS_ flags below */
/* back to stuff that has been around a while (again) */
int32_t fs_contigsumsize; /* size of cluster summary array */
int32_t fs_maxsymlinklen; /* max length of an internal symlink */
int32_t fs_old_inodefmt; /* format of on-disk inodes */
u_int64_t fs_maxfilesize; /* maximum representable file size */
int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
int32_t fs_state; /* validate fs_clean field (UNUSED) */
int32_t fs_old_postblformat; /* format of positional layout tables */
int32_t fs_old_nrpos; /* number of rotational positions */
int32_t fs_spare5[2]; /* old fs_postbloff */
/* old fs_rotbloff */
int32_t fs_magic; /* magic number */
};
 
#define fs_old_postbloff fs_spare5[0]
#define fs_old_rotbloff fs_spare5[1]
#define fs_old_postbl_start fs_maxbsize
#define fs_old_headswitch fs_id[0]
#define fs_old_trkseek fs_id[1]
#define fs_old_csmask fs_spare1[0]
#define fs_old_csshift fs_spare1[1]
 
#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
 
#define old_fs_postbl(fs_, cylno, opostblsave) \
((((fs_)->fs_old_postblformat == FS_42POSTBLFMT) || \
((fs_)->fs_old_postbloff == offsetof(struct fs, fs_old_postbl_start))) \
? ((int16_t *)(opostblsave) + (cylno) * (fs_)->fs_old_nrpos) \
: ((int16_t *)((uint8_t *)(fs_) + \
(fs_)->fs_old_postbloff) + (cylno) * (fs_)->fs_old_nrpos))
#define old_fs_rotbl(fs) \
(((fs)->fs_old_postblformat == FS_42POSTBLFMT) \
? ((uint8_t *)(&(fs)->fs_magic+1)) \
: ((uint8_t *)((uint8_t *)(fs) + (fs)->fs_old_rotbloff)))
 
/*
* File system identification
*/
#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast file system magic number */
#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast file system magic number */
#define FS_UFS1_MAGIC_SWAPPED 0x54190100
#define FS_UFS2_MAGIC_SWAPPED 0x19015419
#define FS_OKAY 0x7c269d38 /* superblock checksum */
#define FS_42INODEFMT -1 /* 4.2BSD inode format */
#define FS_44INODEFMT 2 /* 4.4BSD inode format */
 
/*
* File system clean flags
*/
#define FS_ISCLEAN 0x01
#define FS_WASCLEAN 0x02
 
/*
* Preference for optimization.
*/
#define FS_OPTTIME 0 /* minimize allocation time */
#define FS_OPTSPACE 1 /* minimize disk fragmentation */
 
/*
* File system flags
*/
#define FS_UNCLEAN 0x001 /* file system not clean at mount (unused) */
#define FS_DOSOFTDEP 0x002 /* file system using soft dependencies */
#define FS_NEEDSFSCK 0x004 /* needs sync fsck (FreeBSD compat, unused) */
#define FS_INDEXDIRS 0x008 /* kernel supports indexed directories */
#define FS_ACLS 0x010 /* file system has ACLs enabled */
#define FS_MULTILABEL 0x020 /* file system is MAC multi-label */
#define FS_GJOURNAL 0x40 /* gjournaled file system */
#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
#define FS_DOWAPBL 0x100 /* Write ahead physical block logging */
#define FS_DOQUOTA2 0x200 /* in-filesystem quotas */
 
/* File system flags that are ok for NetBSD if set in fs_flags */
#define FS_KNOWN_FLAGS (FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2)
 
/*
* File system internal flags, also in fs_flags.
* (Pick highest number to avoid conflicts with others)
*/
#define FS_SWAPPED 0x80000000 /* file system is endian swapped */
#define FS_INTERNAL 0x80000000 /* mask for internal flags */
 
/*
* Macros to access bits in the fs_active array.
*/
#define ACTIVECG_SET(fs, cg) \
do { \
if ((fs)->fs_active != NULL) \
setbit((fs)->fs_active, (cg)); \
} while (/*CONSTCOND*/ 0)
#define ACTIVECG_CLR(fs, cg) \
do { \
if ((fs)->fs_active != NULL) \
clrbit((fs)->fs_active, (cg)); \
} while (/*CONSTCOND*/ 0)
#define ACTIVECG_ISSET(fs, cg) \
((fs)->fs_active != NULL && isset((fs)->fs_active, (cg)))
 
/*
* The size of a cylinder group is calculated by CGSIZE. The maximum size
* is limited by the fact that cylinder groups are at most one block.
* Its size is derived from the size of the maps maintained in the
* cylinder group and the (struct cg) size.
*/
#define CGSIZE_IF(fs, ipg, fpg) \
/* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \
/* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \
/* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \
/* inode map */ howmany((ipg), NBBY) + \
/* block map */ howmany((fpg), NBBY) +\
/* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
/* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \
/* cluster map */ howmany(fragstoblks(fs, (fpg)), NBBY)))
 
#define CGSIZE(fs) CGSIZE_IF((fs), (fs)->fs_ipg, (fs)->fs_fpg)
 
/*
* The minimal number of cylinder groups that should be created.
*/
#define MINCYLGRPS 4
 
 
/*
* Convert cylinder group to base address of its global summary info.
*/
#define fs_cs(fs, indx) fs_csp[indx]
 
/*
* Cylinder group block for a file system.
*/
#define CG_MAGIC 0x090255
struct cg {
int32_t cg_firstfield; /* historic cyl groups linked list */
int32_t cg_magic; /* magic number */
int32_t cg_old_time; /* time last written */
int32_t cg_cgx; /* we are the cgx'th cylinder group */
int16_t cg_old_ncyl; /* number of cyl's this cg */
int16_t cg_old_niblk; /* number of inode blocks this cg */
int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int32_t cg_rotor; /* position of last used block */
int32_t cg_frotor; /* position of last used frag */
int32_t cg_irotor; /* position of last used inode */
int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
int32_t cg_old_btotoff; /* (int32) block totals per cylinder */
int32_t cg_old_boff; /* (u_int16) free block positions */
int32_t cg_iusedoff; /* (u_int8) used inode map */
int32_t cg_freeoff; /* (u_int8) free block map */
int32_t cg_nextfreeoff; /* (u_int8) next available space */
int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */
int32_t cg_clusteroff; /* (u_int8) free cluster map */
int32_t cg_nclusterblks; /* number of clusters this cg */
int32_t cg_niblk; /* number of inode blocks this cg */
int32_t cg_initediblk; /* last initialized inode */
int32_t cg_sparecon32[3]; /* reserved for future use */
int64_t cg_time; /* time last written */
int64_t cg_sparecon64[3]; /* reserved for future use */
u_int8_t cg_space[1]; /* space for cylinder group maps */
/* actually longer */
};
 
/*
* The following structure is defined
* for compatibility with old file systems.
*/
struct ocg {
int32_t cg_firstfield; /* historic linked list of cyl groups */
int32_t cg_unused_1; /* used for incore cyl groups */
int32_t cg_time; /* time last written */
int32_t cg_cgx; /* we are the cgx'th cylinder group */
int16_t cg_ncyl; /* number of cyl's this cg */
int16_t cg_niblk; /* number of inode blocks this cg */
int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int32_t cg_rotor; /* position of last used block */
int32_t cg_frotor; /* position of last used frag */
int32_t cg_irotor; /* position of last used inode */
int32_t cg_frsum[8]; /* counts of available frags */
int32_t cg_btot[32]; /* block totals per cylinder */
int16_t cg_b[32][8]; /* positions of free blocks */
u_int8_t cg_iused[256]; /* used inode map */
int32_t cg_magic; /* magic number */
u_int8_t cg_free[1]; /* free block map */
/* actually longer */
};
 
 
/*
* Macros for access to cylinder group array structures.
*/
#define old_cg_blktot_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_btot)
#define old_cg_blks_old(fs, cgp, cylno, ns) \
(((struct ocg *)(cgp))->cg_b[cylno])
 
#define old_cg_blktot_new(cgp, ns) \
((int32_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_old_btotoff, (ns))))
#define old_cg_blks_new(fs, cgp, cylno, ns) \
((int16_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_old_boff, (ns))) + (cylno) * (fs)->fs_old_nrpos)
 
#define old_cg_blktot(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
old_cg_blktot_old(cgp, ns) : old_cg_blktot_new(cgp, ns))
#define old_cg_blks(fs, cgp, cylno, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
old_cg_blks_old(fs, cgp, cylno, ns) : old_cg_blks_new(fs, cgp, cylno, ns))
 
#define cg_inosused_new(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_iusedoff, (ns))))
#define cg_blksfree_new(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_freeoff, (ns))))
#define cg_chkmagic_new(cgp, ns) \
(ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
 
#define cg_inosused_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_iused)
#define cg_blksfree_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_free)
#define cg_chkmagic_old(cgp, ns) \
(ufs_rw32(((struct ocg *)(cgp))->cg_magic, (ns)) == CG_MAGIC)
 
#define cg_inosused(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
cg_inosused_old(cgp, ns) : cg_inosused_new(cgp, ns))
#define cg_blksfree(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
cg_blksfree_old(cgp, ns) : cg_blksfree_new(cgp, ns))
#define cg_chkmagic(cgp, ns) \
(cg_chkmagic_new(cgp, ns) || cg_chkmagic_old(cgp, ns))
 
#define cg_clustersfree(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_clusteroff, (ns))))
#define cg_clustersum(cgp, ns) \
((int32_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_clustersumoff, (ns))))
 
 
/*
* Turn file system block numbers into disk block addresses.
* This maps file system blocks to device size blocks.
*/
#if defined (_KERNEL)
#define fsbtodb(fs, b) ((b) << ((fs)->fs_fshift - DEV_BSHIFT))
#define dbtofsb(fs, b) ((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
#else
#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
#endif
 
/*
* Cylinder group macros to locate things in cylinder groups.
* They calc file system addresses of cylinder group data structures.
*/
#define cgbase(fs, c) (((daddr_t)(fs)->fs_fpg) * (c))
#define cgstart_ufs1(fs, c) \
(cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))
#define cgstart_ufs2(fs, c) cgbase((fs), (c))
#define cgstart(fs, c) ((fs)->fs_magic == FS_UFS2_MAGIC \
? cgstart_ufs2((fs), (c)) : cgstart_ufs1((fs), (c)))
#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
 
/*
* Macros for handling inode numbers:
* inode number to file system block offset.
* inode number to cylinder group number.
* inode number to file system block address.
*/
#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
#define ino_to_fsba(fs, x) \
((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
 
/*
* Give cylinder group number for a file system block.
* Give cylinder group block number for a file system block.
*/
#define dtog(fs, d) ((d) / (fs)->fs_fpg)
#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
 
/*
* Extract the bits for a block from a map.
* Compute the cylinder and rotational position of a cyl block addr.
*/
#define blkmap(fs, map, loc) \
(((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
#define old_cbtocylno(fs, bno) \
(fsbtodb(fs, bno) / (fs)->fs_old_spc)
#define old_cbtorpos(fs, bno) \
((fs)->fs_old_nrpos <= 1 ? 0 : \
(fsbtodb(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
fsbtodb(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
(fs)->fs_old_nsect * (fs)->fs_old_nrpos / (fs)->fs_old_npsect)
 
/*
* The following macros optimize certain frequently calculated
* quantities by using shifts and masks in place of divisions
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
((loc) & (fs)->fs_qbmask)
#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
((loc) & (fs)->fs_qfmask)
#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
(((off_t)(frag)) << (fs)->fs_fshift)
#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
(((off_t)(blk)) << (fs)->fs_bshift)
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
((loc) >> (fs)->fs_bshift)
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
((loc) >> (fs)->fs_fshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
(((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
(((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
((frags) >> (fs)->fs_fragshift)
#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
((blks) << (fs)->fs_fragshift)
#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
((fsb) & ((fs)->fs_frag - 1))
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
((fsb) &~ ((fs)->fs_frag - 1))
 
/*
* Determine the number of available frags given a
* percentage to hold in reserve.
*/
#define freespace(fs, percentreserved) \
(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
(fs)->fs_cstotal.cs_nffree - \
(((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
 
/*
* Determining the size of a file block in the file system.
*/
#define blksize(fs, ip, lbn) \
(((lbn) >= NDADDR || (ip)->i_size >= lblktosize(fs, (lbn) + 1)) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_size))))
 
#define sblksize(fs, size, lbn) \
(((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (size)))))
 
 
/*
* Number of inodes in a secondary storage block/fragment.
*/
#define INOPB(fs) ((fs)->fs_inopb)
#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
 
/*
* Number of indirects in a file system block.
*/
#define NINDIR(fs) ((fs)->fs_nindir)
 
/*
* Apple UFS Label:
* We check for this to decide to use APPLEUFS_DIRBLKSIZ
*/
#define APPLEUFS_LABEL_MAGIC 0x4c41424c /* LABL */
#define APPLEUFS_LABEL_SIZE 1024
#define APPLEUFS_LABEL_OFFSET (BBSIZE - APPLEUFS_LABEL_SIZE) /* located at 7k */
#define APPLEUFS_LABEL_VERSION 1
#define APPLEUFS_MAX_LABEL_NAME 512
 
struct appleufslabel {
u_int32_t ul_magic;
u_int16_t ul_checksum;
u_int16_t ul_unused0;
u_int32_t ul_version;
u_int32_t ul_time;
u_int16_t ul_namelen;
u_char ul_name[APPLEUFS_MAX_LABEL_NAME]; /* Warning: may not be null terminated */
u_int16_t ul_unused1;
u_int64_t ul_uuid; /* Note this is only 4 byte aligned */
u_char ul_reserved[24];
u_char ul_unused[460];
} __packed;
 
 
#endif /* !_UFS_FFS_FS_H_ */
/disk/tools/fs-NetBSD/loader/biolib.s
0,0 → 1,26
;
; biolib.s -- basic I/O library
;
 
.set cin,0xE0000010
.set cout,0xE0000018
.set dskio,0xE0000030
 
.export getc
.export putc
.export rwscts
 
.code
.align 4
 
getc:
add $8,$0,cin
jr $8
 
putc:
add $8,$0,cout
jr $8
 
rwscts:
add $8,$0,dskio
jr $8
/disk/tools/fs-NetBSD/loader/c0.s
0,0 → 1,59
;
; c0.s -- startup code and begin-of-segment labels
;
 
.import main
 
.import _ecode
.import _edata
.import _ebss
 
.export _bcode
.export _bdata
.export _bbss
 
.import bootDisk
.import startSector
.import numSectors
.import entryPoint
 
.code
_bcode:
 
start:
add $10,$0,_bdata ; copy data segment
add $8,$0,_edata
sub $9,$8,$10
add $9,$9,_ecode
j cpytest
cpyloop:
ldw $11,$9,0
stw $11,$8,0
cpytest:
sub $8,$8,4
sub $9,$9,4
bgeu $8,$10,cpyloop
add $8,$0,_bbss ; clear bss segment
add $9,$0,_ebss
j clrtest
clrloop:
stw $0,$8,0
add $8,$8,4
clrtest:
bltu $8,$9,clrloop
add $29,$0,0xC0400000 ; setup stack
stw $16,$0,bootDisk ; make arguments available
stw $17,$0,startSector
stw $18,$0,numSectors
jal main ; call 'main' function
ldw $16,$0,bootDisk ; setup arguments for next stage
ldw $17,$0,startSector
ldw $18,$0,numSectors
ldw $31,$0,entryPoint ; jump to loaded program
jr $31
 
.data
_bdata:
 
.bss
_bbss:
/disk/tools/fs-NetBSD/loader/c1.s
0,0 → 1,19
;
; c1.s -- end-of-segment labels
;
 
.export _ecode
.export _edata
.export _ebss
 
.code
.align 4
_ecode:
 
.data
.align 4
_edata:
 
.bss
.align 4
_ebss:
/disk/tools/fs-NetBSD/loader/dir.h
0,0 → 1,160
/* $NetBSD: dir.h,v 1.21 2009/07/22 04:49:19 dholland Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dir.h 8.5 (Berkeley) 4/27/95
*/
 
#ifndef _UFS_UFS_DIR_H_
#define _UFS_UFS_DIR_H_
 
/*
* Theoretically, directories can be more than 2Gb in length; however, in
* practice this seems unlikely. So, we define the type doff_t as a 32-bit
* quantity to keep down the cost of doing lookup on a 32-bit machine.
*/
#define doff_t int32_t
#define MAXDIRSIZE (0x7fffffff)
 
/*
* A directory consists of some number of blocks of DIRBLKSIZ
* bytes, where DIRBLKSIZ is chosen such that it can be transferred
* to disk in a single atomic operation (e.g. 512 bytes on most machines).
*
* Each DIRBLKSIZ byte block contains some number of directory entry
* structures, which are of variable length. Each directory entry has
* a struct direct at the front of it, containing its inode number,
* the length of the entry, and the length of the name contained in
* the entry. These are followed by the name padded to a 4 byte boundary.
* All names are guaranteed null terminated.
* The maximum length of a name in a directory is FFS_MAXNAMLEN.
*
* The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
* a directory entry. Free space in a directory is represented by
* entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZ bytes
* in a directory block are claimed by the directory entries. This
* usually results in the last entry in a directory having a large
* dp->d_reclen. When entries are deleted from a directory, the
* space is returned to the previous entry in the same directory
* block by increasing its dp->d_reclen. If the first entry of
* a directory block is free, then its dp->d_ino is set to 0.
* Entries other than the first in a directory do not normally have
* dp->d_ino set to 0.
*/
#undef DIRBLKSIZ
#define DIRBLKSIZ DEV_BSIZE
#define FFS_MAXNAMLEN 255
#define APPLEUFS_DIRBLKSIZ 1024
 
#define d_ino d_fileno
struct direct {
u_int32_t d_fileno; /* inode number of entry */
u_int16_t d_reclen; /* length of this record */
u_int8_t d_type; /* file type, see below */
u_int8_t d_namlen; /* length of string in d_name */
char d_name[FFS_MAXNAMLEN + 1];/* name with length <= FFS_MAXNAMLEN */
};
 
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
 
/*
* Convert between stat structure types and directory types.
*/
#define IFTODT(mode) (((mode) & 0170000) >> 12)
#define DTTOIF(dirtype) ((dirtype) << 12)
 
/*
* The DIRSIZ macro gives the minimum record length which will hold
* the directory entry. This requires the amount of space in struct direct
* without the d_name field, plus enough space for the name with a terminating
* null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
*/
#define DIRECTSIZ(namlen) \
((sizeof(struct direct) - (FFS_MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3))
 
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && !(needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#else
#define DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && (needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#endif
 
#define OLDDIRFMT 1
#define NEWDIRFMT 0
 
/*
* Template for manipulating directories. Should use struct direct's,
* but the name field is FFS_MAXNAMLEN - 1, and this just won't do.
*/
struct dirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int8_t dot_type;
u_int8_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int8_t dotdot_type;
u_int8_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
 
/*
* This is the old format of directories, sanz type element.
*/
struct odirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int16_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int16_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
#endif /* !_UFS_UFS_DIR_H_ */
/disk/tools/fs-NetBSD/loader/auxlib.c
0,0 → 1,333
/*
* auxlib.c -- auxiliary library for standalone programs
*/
 
 
#include "types.h"
#include "stdarg.h"
#include "auxlib.h"
#include "biolib.h"
 
 
/**************************************************************/
 
/* string functions */
 
 
int strlen(char *str) {
int i;
 
i = 0;
while (*str++ != '\0') {
i++;
}
return i;
}
 
 
int strcmp(char *str1, char *str2) {
while (*str1 == *str2) {
if (*str1 == '\0') {
return 0;
}
str1++;
str2++;
}
return (* (unsigned char *) str1) - (* (unsigned char *) str2);
}
 
 
void strcpy(char *dst, char *src) {
while ((*dst++ = *src++) != '\0') ;
}
 
 
/**************************************************************/
 
/* terminal I/O */
 
 
/*
* Input a character from the console.
*/
char getchar(void) {
return getc();
}
 
 
/*
* Output a character on the console.
* Replace LF by CR/LF.
*/
void putchar(char c) {
if (c == '\n') {
putchar('\r');
}
putc(c);
}
 
 
/**************************************************************/
 
/* get a line from the terminal */
 
 
void getLine(char *prompt, char *line, int max) {
int index;
char c;
 
printf("%s%s", prompt, line);
index = strlen(line);
while (1) {
c = getchar();
switch (c) {
case '\r':
putchar('\n');
line[index] = '\0';
return;
case '\b':
case 0x7F:
if (index == 0) {
break;
}
putchar('\b');
putchar(' ');
putchar('\b');
index--;
break;
default:
if (c == '\t') {
c = ' ';
}
if (c < 0x20 || c > 0x7E) {
break;
}
putchar(c);
line[index++] = c;
break;
}
}
}
 
 
/**************************************************************/
 
/* scaled-down version of printf */
 
 
/*
* Count the number of characters needed to represent
* a given number in base 10.
*/
static int countPrintn(long n) {
long a;
int res;
 
res = 0;
if (n < 0) {
res++;
n = -n;
}
a = n / 10;
if (a != 0) {
res += countPrintn(a);
}
return res + 1;
}
 
 
/*
* Output a number in base 10.
*/
static void printn(long n) {
long a;
 
if (n < 0) {
putchar('-');
n = -n;
}
a = n / 10;
if (a != 0) {
printn(a);
}
putchar(n % 10 + '0');
}
 
 
/*
* Count the number of characters needed to represent
* a given number in a given base.
*/
static int countPrintu(unsigned long n, unsigned long b) {
unsigned long a;
int res;
 
res = 0;
a = n / b;
if (a != 0) {
res += countPrintu(a, b);
}
return res + 1;
}
 
 
/*
* Output a number in a given base.
*/
static void printu(unsigned long n, unsigned long b, Bool upperCase) {
unsigned long a;
 
a = n / b;
if (a != 0) {
printu(a, b, upperCase);
}
if (upperCase) {
putchar("0123456789ABCDEF"[n % b]);
} else {
putchar("0123456789abcdef"[n % b]);
}
}
 
 
/*
* Output a number of filler characters.
*/
static void fill(int numFillers, char filler) {
while (numFillers-- > 0) {
putchar(filler);
}
}
 
 
/*
* Formatted output with a variable argument list.
*/
void vprintf(char *fmt, va_list ap) {
char c;
int n;
long ln;
unsigned int u;
unsigned long lu;
char *s;
Bool negFlag;
char filler;
int width, count;
 
while (1) {
while ((c = *fmt++) != '%') {
if (c == '\0') {
return;
}
putchar(c);
}
c = *fmt++;
if (c == '-') {
negFlag = TRUE;
c = *fmt++;
} else {
negFlag = FALSE;
}
if (c == '0') {
filler = '0';
c = *fmt++;
} else {
filler = ' ';
}
width = 0;
while (c >= '0' && c <= '9') {
width *= 10;
width += c - '0';
c = *fmt++;
}
if (c == 'd') {
n = va_arg(ap, int);
count = countPrintn(n);
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printn(n);
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
u = va_arg(ap, int);
count = countPrintu(u,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printu(u,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
c == 'X');
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'l') {
c = *fmt++;
if (c == 'd') {
ln = va_arg(ap, long);
count = countPrintn(ln);
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printn(ln);
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
lu = va_arg(ap, long);
count = countPrintu(lu,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printu(lu,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
c == 'X');
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else {
putchar('l');
putchar(c);
}
} else
if (c == 's') {
s = va_arg(ap, char *);
count = strlen(s);
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
while ((c = *s++) != '\0') {
putchar(c);
}
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'c') {
c = va_arg(ap, char);
putchar(c);
} else {
putchar(c);
}
}
}
 
 
/*
* Formatted output.
* This is a scaled-down version of the C library's
* printf. Used to print diagnostic information on
* the console (and optionally to a logfile).
*/
void printf(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
/disk/tools/fs-NetBSD/loader/auxlib.h
0,0 → 1,23
/*
* auxlib.h -- auxiliary library for standalone programs
*/
 
 
#ifndef _AUXLIB_H_
#define _AUXLIB_H_
 
 
int strlen(char *str);
int strcmp(char *str1, char *str2);
void strcpy(char *dst, char *src);
 
char getchar(void);
void putchar(char c);
 
void getLine(char *prompt, char *line, int max);
 
void vprintf(char *fmt, va_list ap);
void printf(char *fmt, ...);
 
 
#endif /* _AUXLIB_H_ */
/disk/tools/fs-NetBSD/loader/stdarg.h
0,0 → 1,41
/*
* stdarg.h -- variable argument lists
*/
 
 
#ifndef _STDARG_H_
#define _STDARG_H_
 
 
typedef char *va_list;
 
 
static float __va_arg_tmp;
 
 
#define va_start(list, start) \
((void)((list) = (sizeof(start)<4 ? \
(char *)((int *)&(start)+1) : (char *)(&(start)+1))))
 
#define __va_arg(list, mode, n) \
(__typecode(mode)==1 && sizeof(mode)==4 ? \
(__va_arg_tmp = *(double *)(&(list += \
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \
*(mode *)&__va_arg_tmp) : \
*(mode *)(&(list += \
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)]))
 
#define _bigendian_va_arg(list, mode, n) \
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \
__va_arg(list, mode, n))
 
#define va_end(list) ((void)0)
 
#define va_arg(list, mode) \
(sizeof(mode)==8 ? \
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \
_bigendian_va_arg(list, mode, 3U))
 
 
#endif /* _STDARG_H_ */
/disk/tools/fs-NetBSD/loader/Makefile
0,0 → 1,35
#
# Makefile to build the NetBSD system loader
#
 
BUILD = ../../../../build
 
.PHONY: all install clean
 
all: loader
 
install: loader
mkdir -p $(BUILD)/run/fs-NetBSD
cp loader $(BUILD)/run/fs-NetBSD
 
loader: c0.o loader.o auxlib.o biolib.o c1.o
$(BUILD)/bin/ld -h -rc 0xC0300000 -o loader \
c0.o loader.o auxlib.o biolib.o c1.o
 
c0.o: c0.s
$(BUILD)/bin/as -o c0.o c0.s
 
loader.o: loader.c
$(BUILD)/bin/lcc -A -c -o loader.o loader.c
 
auxlib.o: auxlib.c
$(BUILD)/bin/lcc -A -c -o auxlib.o auxlib.c
 
biolib.o: biolib.s
$(BUILD)/bin/as -o biolib.o biolib.s
 
c1.o: c1.s
$(BUILD)/bin/as -o c1.o c1.s
 
clean:
rm -f *~ c0.o loader.o auxlib.o biolib.o c1.o loader
/disk/tools/fs-NetBSD/makefs/walk.c
0,0 → 1,685
/* $NetBSD: walk.c,v 1.25 2012/01/28 02:35:46 christos Exp $ */
 
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: walk.c,v 1.25 2012/01/28 02:35:46 christos Exp $");
#endif /* !__lint */
 
#include <sys/param.h>
 
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
 
#include "common.h"
#include "makefs.h"
#include "mtree.h"
 
static void apply_specdir(const char *, NODE *, fsnode *, int);
static void apply_specentry(const char *, NODE *, fsnode *);
static fsnode *create_fsnode(const char *, const char *, const char *,
struct stat *);
static fsinode *link_check(fsinode *);
 
 
/*
* walk_dir --
* build a tree of fsnodes from `root' and `dir', with a parent
* fsnode of `parent' (which may be NULL for the root of the tree).
* append the tree to a fsnode of `join' if it is not NULL.
* each "level" is a directory, with the "." entry guaranteed to be
* at the start of the list, and without ".." entries.
*/
fsnode *
walk_dir(const char *root, const char *dir, fsnode *parent, fsnode *join)
{
fsnode *first, *cur, *prev, *last;
DIR *dirp;
struct dirent *dent;
char path[MAXPATHLEN + 1];
struct stat stbuf;
char *name, *rp;
int dot, len;
 
assert(root != NULL);
assert(dir != NULL);
 
len = snprintf(path, sizeof(path), "%s/%s", root, dir);
if (len >= (int)sizeof(path))
errx(1, "Pathname too long.");
if (debug & DEBUG_WALK_DIR)
printf("walk_dir: %s %p\n", path, parent);
if ((dirp = opendir(path)) == NULL)
err(1, "Can't opendir `%s'", path);
rp = path + strlen(root) + 1;
if (join != NULL) {
first = cur = join;
while (cur->next != NULL)
cur = cur->next;
prev = last = cur;
} else
last = first = prev = NULL;
while ((dent = readdir(dirp)) != NULL) {
name = dent->d_name;
dot = 0;
if (name[0] == '.')
switch (name[1]) {
case '\0': /* "." */
if (join != NULL)
continue;
dot = 1;
break;
case '.': /* ".." */
if (name[2] == '\0')
continue;
/* FALLTHROUGH */
default:
dot = 0;
}
if (debug & DEBUG_WALK_DIR_NODE)
printf("scanning %s/%s/%s\n", root, dir, name);
if (snprintf(path + len, sizeof(path) - len, "/%s", name) >=
(int)sizeof(path) - len)
errx(1, "Pathname too long.");
if (lstat(path, &stbuf) == -1)
err(1, "Can't lstat `%s'", path);
#ifdef S_ISSOCK
if (S_ISSOCK(stbuf.st_mode & S_IFMT)) {
if (debug & DEBUG_WALK_DIR_NODE)
printf(" skipping socket %s\n", path);
continue;
}
#endif
 
if (join != NULL) {
cur = join->next;
for (;;) {
if (cur == NULL || strcmp(cur->name, name) == 0)
break;
if (cur == last) {
cur = NULL;
break;
}
cur = cur->next;
}
if (cur != NULL) {
if (S_ISDIR(cur->type) &&
S_ISDIR(stbuf.st_mode)) {
if (debug & DEBUG_WALK_DIR_NODE)
printf("merging %s with %p\n",
path, cur->child);
cur->child = walk_dir(root, rp, cur,
cur->child);
continue;
}
errx(1, "Can't merge %s `%s' with existing %s",
inode_type(stbuf.st_mode), path,
inode_type(cur->type));
}
}
 
cur = create_fsnode(root, dir, name, &stbuf);
cur->parent = parent;
if (dot) {
/* ensure "." is at the start of the list */
cur->next = first;
first = cur;
if (! prev)
prev = cur;
cur->first = first;
} else { /* not "." */
if (prev)
prev->next = cur;
prev = cur;
if (!first)
first = cur;
cur->first = first;
if (S_ISDIR(cur->type)) {
cur->child = walk_dir(root, rp, cur, NULL);
continue;
}
}
if (stbuf.st_nlink > 1) {
fsinode *curino;
 
curino = link_check(cur->inode);
if (curino != NULL) {
free(cur->inode);
cur->inode = curino;
cur->inode->nlink++;
if (debug & DEBUG_WALK_DIR_LINKCHECK)
printf("link_check: found [%llu, %llu]\n",
(unsigned long long)curino->st.st_dev,
(unsigned long long)curino->st.st_ino);
}
}
if (S_ISLNK(cur->type)) {
char slink[PATH_MAX+1];
int llen;
 
llen = readlink(path, slink, sizeof(slink) - 1);
if (llen == -1)
err(1, "Readlink `%s'", path);
slink[llen] = '\0';
if ((cur->symlink = strdup(slink)) == NULL)
err(1, "Memory allocation error");
}
}
assert(first != NULL);
if (join == NULL)
for (cur = first->next; cur != NULL; cur = cur->next)
cur->first = first;
if (closedir(dirp) == -1)
err(1, "Can't closedir `%s/%s'", root, dir);
return (first);
}
 
static fsnode *
create_fsnode(const char *root, const char *path, const char *name,
struct stat *stbuf)
{
fsnode *cur;
 
if ((cur = calloc(1, sizeof(fsnode))) == NULL ||
(cur->path = strdup(path)) == NULL ||
(cur->name = strdup(name)) == NULL ||
(cur->inode = calloc(1, sizeof(fsinode))) == NULL)
err(1, "Memory allocation error");
cur->root = root;
cur->type = stbuf->st_mode & S_IFMT;
cur->inode->nlink = 1;
cur->inode->st = *stbuf;
return (cur);
}
 
/*
* free_fsnodes --
* Removes node from tree and frees it and all of
* its decendents.
*/
void
free_fsnodes(fsnode *node)
{
fsnode *cur, *next;
 
assert(node != NULL);
 
/* for ".", start with actual parent node */
if (node->first == node) {
assert(node->name[0] == '.' && node->name[1] == '\0');
if (node->parent) {
assert(node->parent->child == node);
node = node->parent;
}
}
 
/* Find ourselves in our sibling list and unlink */
if (node->first != node) {
for (cur = node->first; cur->next; cur = cur->next) {
if (cur->next == node) {
cur->next = node->next;
node->next = NULL;
break;
}
}
}
 
for (cur = node; cur != NULL; cur = next) {
next = cur->next;
if (cur->child) {
cur->child->parent = NULL;
free_fsnodes(cur->child);
}
if (cur->inode->nlink-- == 1)
free(cur->inode);
if (cur->symlink)
free(cur->symlink);
free(cur->path);
free(cur->name);
free(cur);
}
}
 
/*
* apply_specfile --
* read in the mtree(8) specfile, and apply it to the tree
* at dir,parent. parameters in parent on equivalent types
* will be changed to those found in specfile, and missing
* entries will be added.
*/
void
apply_specfile(const char *specfile, const char *dir, fsnode *parent, int speconly)
{
struct timeval start;
FILE *fp;
NODE *root;
 
assert(specfile != NULL);
assert(parent != NULL);
 
if (debug & DEBUG_APPLY_SPECFILE)
printf("apply_specfile: %s, %s %p\n", specfile, dir, parent);
 
/* read in the specfile */
if ((fp = fopen(specfile, "r")) == NULL)
err(1, "Can't open `%s'", specfile);
TIMER_START(start);
/* !!!!! HG: */
//root = spec(fp);
root = NULL;
/* :HG !!!!! */
TIMER_RESULTS(start, "spec");
if (fclose(fp) == EOF)
err(1, "Can't close `%s'", specfile);
 
/* perform some sanity checks */
if (root == NULL)
errx(1, "Specfile `%s' did not contain a tree", specfile);
assert(strcmp(root->name, ".") == 0);
assert(root->type == F_DIR);
 
/* merge in the changes */
apply_specdir(dir, root, parent, speconly);
 
/* !!!!! HG: */
//free_nodes(root);
/* :HG !!!!! */
}
 
static void
apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode, int speconly)
{
char path[MAXPATHLEN + 1];
NODE *curnode;
fsnode *curfsnode;
 
assert(specnode != NULL);
assert(dirnode != NULL);
 
if (debug & DEBUG_APPLY_SPECFILE)
printf("apply_specdir: %s %p %p\n", dir, specnode, dirnode);
 
if (specnode->type != F_DIR)
errx(1, "Specfile node `%s/%s' is not a directory",
dir, specnode->name);
if (dirnode->type != S_IFDIR)
errx(1, "Directory node `%s/%s' is not a directory",
dir, dirnode->name);
 
apply_specentry(dir, specnode, dirnode);
 
/* Remove any filesystem nodes not found in specfile */
/* XXX inefficient. This is O^2 in each dir and it would
* have been better never to have walked this part of the tree
* to begin with
*/
if (speconly) {
fsnode *next;
assert(dirnode->name[0] == '.' && dirnode->name[1] == '\0');
for (curfsnode = dirnode->next; curfsnode != NULL; curfsnode = next) {
next = curfsnode->next;
for (curnode = specnode->child; curnode != NULL;
curnode = curnode->next) {
if (strcmp(curnode->name, curfsnode->name) == 0)
break;
}
if (curnode == NULL) {
if (debug & DEBUG_APPLY_SPECONLY) {
printf("apply_specdir: trimming %s/%s %p\n", dir, curfsnode->name, curfsnode);
}
free_fsnodes(curfsnode);
}
}
}
 
/* now walk specnode->child matching up with dirnode */
for (curnode = specnode->child; curnode != NULL;
curnode = curnode->next) {
if (debug & DEBUG_APPLY_SPECENTRY)
printf("apply_specdir: spec %s\n",
curnode->name);
for (curfsnode = dirnode->next; curfsnode != NULL;
curfsnode = curfsnode->next) {
#if 0 /* too verbose for now */
if (debug & DEBUG_APPLY_SPECENTRY)
printf("apply_specdir: dirent %s\n",
curfsnode->name);
#endif
if (strcmp(curnode->name, curfsnode->name) == 0)
break;
}
if (snprintf(path, sizeof(path), "%s/%s",
dir, curnode->name) >= sizeof(path))
errx(1, "Pathname too long.");
if (curfsnode == NULL) { /* need new entry */
struct stat stbuf;
 
/*
* don't add optional spec entries
* that lack an existing fs entry
*/
if ((curnode->flags & F_OPT) &&
lstat(path, &stbuf) == -1)
continue;
 
/* check that enough info is provided */
#define NODETEST(t, m) \
if (!(t)) \
errx(1, "`%s': %s not provided", path, m)
NODETEST(curnode->flags & F_TYPE, "type");
NODETEST(curnode->flags & F_MODE, "mode");
/* XXX: require F_TIME ? */
NODETEST(curnode->flags & F_GID ||
curnode->flags & F_GNAME, "group");
NODETEST(curnode->flags & F_UID ||
curnode->flags & F_UNAME, "user");
if (curnode->type == F_BLOCK || curnode->type == F_CHAR)
NODETEST(curnode->flags & F_DEV,
"device number");
#undef NODETEST
 
if (debug & DEBUG_APPLY_SPECFILE)
printf("apply_specdir: adding %s\n",
curnode->name);
/* build minimal fsnode */
memset(&stbuf, 0, sizeof(stbuf));
stbuf.st_mode = nodetoino(curnode->type);
stbuf.st_nlink = 1;
stbuf.st_mtime = stbuf.st_atime =
stbuf.st_ctime = start_time.tv_sec;
#if HAVE_STRUCT_STAT_ST_MTIMENSEC
stbuf.st_mtimensec = stbuf.st_atimensec =
stbuf.st_ctimensec = start_time.tv_nsec;
#endif
curfsnode = create_fsnode(".", ".", curnode->name,
&stbuf);
curfsnode->parent = dirnode->parent;
curfsnode->first = dirnode;
curfsnode->next = dirnode->next;
dirnode->next = curfsnode;
if (curfsnode->type == S_IFDIR) {
/* for dirs, make "." entry as well */
curfsnode->child = create_fsnode(".", ".", ".",
&stbuf);
curfsnode->child->parent = curfsnode;
curfsnode->child->first = curfsnode->child;
}
if (curfsnode->type == S_IFLNK) {
assert(curnode->slink != NULL);
/* for symlinks, copy the target */
if ((curfsnode->symlink =
strdup(curnode->slink)) == NULL)
err(1, "Memory allocation error");
}
}
apply_specentry(dir, curnode, curfsnode);
if (curnode->type == F_DIR) {
if (curfsnode->type != S_IFDIR)
errx(1, "`%s' is not a directory", path);
assert (curfsnode->child != NULL);
apply_specdir(path, curnode, curfsnode->child, speconly);
}
}
}
 
static void
apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
{
 
assert(specnode != NULL);
assert(dirnode != NULL);
 
if (nodetoino(specnode->type) != dirnode->type)
errx(1, "`%s/%s' type mismatch: specfile %s, tree %s",
dir, specnode->name, inode_type(nodetoino(specnode->type)),
inode_type(dirnode->type));
 
if (debug & DEBUG_APPLY_SPECENTRY)
printf("apply_specentry: %s/%s\n", dir, dirnode->name);
 
#define ASEPRINT(t, b, o, n) \
if (debug & DEBUG_APPLY_SPECENTRY) \
printf("\t\t\tchanging %s from " b " to " b "\n", \
t, o, n)
 
if (specnode->flags & (F_GID | F_GNAME)) {
ASEPRINT("gid", "%d",
dirnode->inode->st.st_gid, specnode->st_gid);
dirnode->inode->st.st_gid = specnode->st_gid;
}
if (specnode->flags & F_MODE) {
ASEPRINT("mode", "%#o",
dirnode->inode->st.st_mode & ALLPERMS, specnode->st_mode);
dirnode->inode->st.st_mode &= ~ALLPERMS;
dirnode->inode->st.st_mode |= (specnode->st_mode & ALLPERMS);
}
/* XXX: ignoring F_NLINK for now */
if (specnode->flags & F_SIZE) {
ASEPRINT("size", "%lld",
(long long)dirnode->inode->st.st_size,
(long long)specnode->st_size);
dirnode->inode->st.st_size = specnode->st_size;
}
if (specnode->flags & F_SLINK) {
assert(dirnode->symlink != NULL);
assert(specnode->slink != NULL);
ASEPRINT("symlink", "%s", dirnode->symlink, specnode->slink);
free(dirnode->symlink);
if ((dirnode->symlink = strdup(specnode->slink)) == NULL)
err(1, "Memory allocation error");
}
if (specnode->flags & F_TIME) {
ASEPRINT("time", "%ld",
(long)dirnode->inode->st.st_mtime,
(long)specnode->st_mtimespec.tv_sec);
dirnode->inode->st.st_mtime = specnode->st_mtimespec.tv_sec;
dirnode->inode->st.st_atime = specnode->st_mtimespec.tv_sec;
dirnode->inode->st.st_ctime = start_time.tv_sec;
#if HAVE_STRUCT_STAT_ST_MTIMENSEC
dirnode->inode->st.st_mtimensec = specnode->st_mtimespec.tv_nsec;
dirnode->inode->st.st_atimensec = specnode->st_mtimespec.tv_nsec;
dirnode->inode->st.st_ctimensec = start_time.tv_nsec;
#endif
}
if (specnode->flags & (F_UID | F_UNAME)) {
ASEPRINT("uid", "%d",
dirnode->inode->st.st_uid, specnode->st_uid);
dirnode->inode->st.st_uid = specnode->st_uid;
}
#if HAVE_STRUCT_STAT_ST_FLAGS
if (specnode->flags & F_FLAGS) {
ASEPRINT("flags", "%#lX",
(unsigned long)dirnode->inode->st.st_flags,
(unsigned long)specnode->st_flags);
dirnode->inode->st.st_flags = specnode->st_flags;
}
#endif
if (specnode->flags & F_DEV) {
ASEPRINT("rdev", "%#llx",
(unsigned long long)dirnode->inode->st.st_rdev,
(unsigned long long)specnode->st_rdev);
dirnode->inode->st.st_rdev = specnode->st_rdev;
}
#undef ASEPRINT
 
dirnode->flags |= FSNODE_F_HASSPEC;
}
 
 
/*
* dump_fsnodes --
* dump the fsnodes from `cur'
*/
void
dump_fsnodes(fsnode *root)
{
fsnode *cur;
char path[MAXPATHLEN + 1];
 
printf("dump_fsnodes: %s %p\n", root->path, root);
for (cur = root; cur != NULL; cur = cur->next) {
if (snprintf(path, sizeof(path), "%s/%s", cur->path,
cur->name) >= (int)sizeof(path))
errx(1, "Pathname too long.");
 
if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
printf("cur=%8p parent=%8p first=%8p ",
cur, cur->parent, cur->first);
printf("%7s: %s", inode_type(cur->type), path);
if (S_ISLNK(cur->type)) {
assert(cur->symlink != NULL);
printf(" -> %s", cur->symlink);
} else {
assert (cur->symlink == NULL);
}
if (cur->inode->nlink > 1)
printf(", nlinks=%d", cur->inode->nlink);
putchar('\n');
 
if (cur->child) {
assert (cur->type == S_IFDIR);
dump_fsnodes(cur->child);
}
}
printf("dump_fsnodes: finished %s/%s\n", root->path, root->name);
}
 
 
/*
* inode_type --
* for a given inode type `mode', return a descriptive string.
* for most cases, uses inotype() from mtree/misc.c
*/
const char *
inode_type(mode_t mode)
{
 
if (S_ISLNK(mode))
return ("symlink"); /* inotype() returns "link"... */
return (inotype(mode));
}
 
 
/*
* link_check --
* return pointer to fsinode matching `entry's st_ino & st_dev if it exists,
* otherwise add `entry' to table and return NULL
*/
/* This was borrowed from du.c and tweaked to keep an fsnode
* pointer instead. -- dbj@netbsd.org
*/
static fsinode *
link_check(fsinode *entry)
{
static struct entry {
fsinode *data;
} *htable;
static int htshift; /* log(allocated size) */
static int htmask; /* allocated size - 1 */
static int htused; /* 2*number of insertions */
int h, h2;
uint64_t tmp;
/* this constant is (1<<64)/((1+sqrt(5))/2)
* aka (word size)/(golden ratio)
*/
const uint64_t HTCONST = 11400714819323198485ULL;
const int HTBITS = 64;
/* Never store zero in hashtable */
assert(entry);
 
/* Extend hash table if necessary, keep load under 0.5 */
if (htused<<1 >= htmask) {
struct entry *ohtable;
 
if (!htable)
htshift = 10; /* starting hashtable size */
else
htshift++; /* exponential hashtable growth */
 
htmask = (1 << htshift) - 1;
htused = 0;
 
ohtable = htable;
htable = calloc(htmask+1, sizeof(*htable));
if (!htable)
err(1, "Memory allocation error");
 
/* populate newly allocated hashtable */
if (ohtable) {
int i;
for (i = 0; i <= htmask>>1; i++)
if (ohtable[i].data)
link_check(ohtable[i].data);
free(ohtable);
}
}
 
/* multiplicative hashing */
tmp = entry->st.st_dev;
tmp <<= HTBITS>>1;
tmp |= entry->st.st_ino;
tmp *= HTCONST;
h = tmp >> (HTBITS - htshift);
h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
/* open address hashtable search with double hash probing */
while (htable[h].data) {
if ((htable[h].data->st.st_ino == entry->st.st_ino) &&
(htable[h].data->st.st_dev == entry->st.st_dev)) {
return htable[h].data;
}
h = (h + h2) & htmask;
}
 
/* Insert the current entry into hashtable */
htable[h].data = entry;
htused++;
return NULL;
}
/disk/tools/fs-NetBSD/makefs/ufs_bswap.h
0,0 → 1,80
/* $NetBSD: ufs_bswap.h,v 1.19 2009/10/19 18:41:17 bouyer Exp $ */
 
/*
* Copyright (c) 1998 Manuel Bouyer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
 
#ifndef _UFS_UFS_BSWAP_H_
#define _UFS_UFS_BSWAP_H_
 
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
#endif
 
#include "common.h"
 
/* Macros to access UFS flags */
#ifdef FFS_EI
#define UFS_MPNEEDSWAP(ump) ((ump)->um_flags & UFS_NEEDSWAP)
#define UFS_FSNEEDSWAP(fs) ((fs)->fs_flags & FS_SWAPPED)
#define UFS_IPNEEDSWAP(ip) UFS_MPNEEDSWAP((ip)->i_ump)
#else
#define UFS_MPNEEDSWAP(ump) (0)
#define UFS_FSNEEDSWAP(fs) (0)
#define UFS_IPNEEDSWAP(ip) (0)
#endif
 
#if !defined(_KERNEL) || defined(FFS_EI)
/* inlines for access to swapped data */
static inline u_int16_t
ufs_rw16(uint16_t a, int ns)
{
return ((ns) ? bswap16(a) : (a));
}
 
static inline u_int32_t
ufs_rw32(uint32_t a, int ns)
{
return ((ns) ? bswap32(a) : (a));
}
 
static inline u_int64_t
ufs_rw64(uint64_t a, int ns)
{
return ((ns) ? bswap64(a) : (a));
}
#else
#define ufs_rw16(a, ns) ((uint16_t)(a))
#define ufs_rw32(a, ns) ((uint32_t)(a))
#define ufs_rw64(a, ns) ((uint64_t)(a))
#endif
 
#define ufs_add16(a, b, ns) \
(a) = ufs_rw16(ufs_rw16((a), (ns)) + (b), (ns))
#define ufs_add32(a, b, ns) \
(a) = ufs_rw32(ufs_rw32((a), (ns)) + (b), (ns))
#define ufs_add64(a, b, ns) \
(a) = ufs_rw64(ufs_rw64((a), (ns)) + (b), (ns))
 
#endif /* !_UFS_UFS_BSWAP_H_ */
/disk/tools/fs-NetBSD/makefs/mkfs.c
0,0 → 1,856
/* $NetBSD: mkfs.c,v 1.22 2011/10/09 21:33:43 christos Exp $ */
 
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1980, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95";
#else
#ifdef __RCSID
__RCSID("$NetBSD: mkfs.c,v 1.22 2011/10/09 21:33:43 christos Exp $");
#endif
#endif
#endif /* not lint */
 
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
 
#include "common.h"
#include "makefs.h"
#include "ffs.h"
 
#include "dinode.h"
#include "ufs_bswap.h"
#include "fs.h"
 
#include "ufs_inode.h"
#include "ffs_extern.h"
#include "newfs_extern.h"
 
static void initcg(int, time_t, const fsinfo_t *);
static int ilog2(int);
 
static int count_digits(int);
 
/*
* make file system for cylinder-group style file systems
*/
#define UMASK 0755
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
 
union {
struct fs fs;
char pad[SBLOCKSIZE];
} fsun;
#define sblock fsun.fs
struct csum *fscs;
 
union {
struct cg cg;
char pad[FFS_MAXBSIZE];
} cgun;
#define acg cgun.cg
 
char *iobuf;
int iobufsize;
 
char writebuf[FFS_MAXBSIZE];
 
static int Oflag; /* format as an 4.3BSD file system */
static int64_t fssize; /* file system size */
static int sectorsize; /* bytes/sector */
static int fsize; /* fragment size */
static int bsize; /* block size */
static int maxbsize; /* maximum clustering */
static int maxblkspercg;
static int minfree; /* free space threshold */
static int opt; /* optimization preference (space or time) */
static int density; /* number of bytes per inode */
static int maxcontig; /* max contiguous blocks to allocate */
static int maxbpg; /* maximum blocks per file in a cyl group */
static int bbsize; /* boot block size */
static int sbsize; /* superblock size */
static int avgfilesize; /* expected average file size */
static int avgfpdir; /* expected number of files per directory */
 
struct fs *
ffs_mkfs(const char *fsys, const fsinfo_t *fsopts)
{
int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg;
int32_t cylno, i, csfrags;
long long sizepb;
void *space;
int size, blks;
int nprintcols, printcolwidth;
ffs_opt_t *ffs_opts = fsopts->fs_specific;
 
Oflag = ffs_opts->version;
fssize = fsopts->size / fsopts->sectorsize;
sectorsize = fsopts->sectorsize;
fsize = ffs_opts->fsize;
bsize = ffs_opts->bsize;
maxbsize = ffs_opts->maxbsize;
maxblkspercg = ffs_opts->maxblkspercg;
minfree = ffs_opts->minfree;
opt = ffs_opts->optimization;
density = ffs_opts->density;
maxcontig = ffs_opts->maxcontig;
maxbpg = ffs_opts->maxbpg;
avgfilesize = ffs_opts->avgfilesize;
avgfpdir = ffs_opts->avgfpdir;
bbsize = BBSIZE;
sbsize = SBLOCKSIZE;
 
/* !!!!! HG: */
//strlcpy((char *)sblock.fs_volname, ffs_opts->label,
// sizeof(sblock.fs_volname));
strncpy((char *)sblock.fs_volname, ffs_opts->label,
sizeof(sblock.fs_volname));
/* :HG !!!!! */
 
if (Oflag == 0) {
sblock.fs_old_inodefmt = FS_42INODEFMT;
sblock.fs_maxsymlinklen = 0;
sblock.fs_old_flags = 0;
} else {
sblock.fs_old_inodefmt = FS_44INODEFMT;
sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 :
MAXSYMLINKLEN_UFS2);
sblock.fs_old_flags = FS_FLAGS_UPDATED;
sblock.fs_flags = 0;
}
/*
* Validate the given file system size.
* Verify that its last block can actually be accessed.
* Convert to file system fragment sized units.
*/
if (fssize <= 0) {
printf("preposterous size %lld\n", (long long)fssize);
exit(13);
}
ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts);
 
/*
* collect and verify the filesystem density info
*/
sblock.fs_avgfilesize = avgfilesize;
sblock.fs_avgfpdir = avgfpdir;
if (sblock.fs_avgfilesize <= 0)
printf("illegal expected average file size %d\n",
sblock.fs_avgfilesize), exit(14);
if (sblock.fs_avgfpdir <= 0)
printf("illegal expected number of files per directory %d\n",
sblock.fs_avgfpdir), exit(15);
/*
* collect and verify the block and fragment sizes
*/
sblock.fs_bsize = bsize;
sblock.fs_fsize = fsize;
if (!POWEROF2(sblock.fs_bsize)) {
printf("block size must be a power of 2, not %d\n",
sblock.fs_bsize);
exit(16);
}
if (!POWEROF2(sblock.fs_fsize)) {
printf("fragment size must be a power of 2, not %d\n",
sblock.fs_fsize);
exit(17);
}
if (sblock.fs_fsize < sectorsize) {
printf("fragment size %d is too small, minimum is %d\n",
sblock.fs_fsize, sectorsize);
exit(18);
}
if (sblock.fs_bsize < MINBSIZE) {
printf("block size %d is too small, minimum is %d\n",
sblock.fs_bsize, MINBSIZE);
exit(19);
}
if (sblock.fs_bsize > FFS_MAXBSIZE) {
printf("block size %d is too large, maximum is %d\n",
sblock.fs_bsize, FFS_MAXBSIZE);
exit(19);
}
if (sblock.fs_bsize < sblock.fs_fsize) {
printf("block size (%d) cannot be smaller than fragment size (%d)\n",
sblock.fs_bsize, sblock.fs_fsize);
exit(20);
}
 
if (maxbsize < bsize || !POWEROF2(maxbsize)) {
sblock.fs_maxbsize = sblock.fs_bsize;
printf("Extent size set to %d\n", sblock.fs_maxbsize);
} else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) {
sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize;
printf("Extent size reduced to %d\n", sblock.fs_maxbsize);
} else {
sblock.fs_maxbsize = maxbsize;
}
sblock.fs_maxcontig = maxcontig;
if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) {
sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize;
printf("Maxcontig raised to %d\n", sblock.fs_maxbsize);
}
 
if (sblock.fs_maxcontig > 1)
sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG);
 
sblock.fs_bmask = ~(sblock.fs_bsize - 1);
sblock.fs_fmask = ~(sblock.fs_fsize - 1);
sblock.fs_qbmask = ~sblock.fs_bmask;
sblock.fs_qfmask = ~sblock.fs_fmask;
for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
sblock.fs_bshift++;
for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
sblock.fs_fshift++;
sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
sblock.fs_fragshift++;
if (sblock.fs_frag > MAXFRAG) {
printf("fragment size %d is too small, "
"minimum with block size %d is %d\n",
sblock.fs_fsize, sblock.fs_bsize,
sblock.fs_bsize / MAXFRAG);
exit(21);
}
sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize);
sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
 
if (Oflag <= 1) {
sblock.fs_magic = FS_UFS1_MAGIC;
sblock.fs_sblockloc = SBLOCK_UFS1;
sblock.fs_nindir = sblock.fs_bsize / sizeof(int32_t);
sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode);
sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) *
sizeof (int32_t));
sblock.fs_old_inodefmt = FS_44INODEFMT;
sblock.fs_old_cgoffset = 0;
sblock.fs_old_cgmask = 0xffffffff;
sblock.fs_old_size = sblock.fs_size;
sblock.fs_old_rotdelay = 0;
sblock.fs_old_rps = 60;
sblock.fs_old_nspf = sblock.fs_fsize / sectorsize;
sblock.fs_old_cpg = 1;
sblock.fs_old_interleave = 1;
sblock.fs_old_trackskew = 0;
sblock.fs_old_cpc = 0;
sblock.fs_old_postblformat = 1;
sblock.fs_old_nrpos = 1;
} else {
sblock.fs_magic = FS_UFS2_MAGIC;
#if 0 /* XXX makefs is used for small filesystems. */
sblock.fs_sblockloc = SBLOCK_UFS2;
#else
sblock.fs_sblockloc = SBLOCK_UFS1;
#endif
sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t);
sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) *
sizeof (int64_t));
}
 
sblock.fs_sblkno =
roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize),
sblock.fs_frag);
sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag));
sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) {
sizepb *= NINDIR(&sblock);
sblock.fs_maxfilesize += sizepb;
}
 
/*
* Calculate the number of blocks to put into each cylinder group.
*
* This algorithm selects the number of blocks per cylinder
* group. The first goal is to have at least enough data blocks
* in each cylinder group to meet the density requirement. Once
* this goal is achieved we try to expand to have at least
* 1 cylinder group. Once this goal is achieved, we pack as
* many blocks into each cylinder group map as will fit.
*
* We start by calculating the smallest number of blocks that we
* can put into each cylinder group. If this is too big, we reduce
* the density until it fits.
*/
origdensity = density;
for (;;) {
fragsperinode = MAX(numfrags(&sblock, density), 1);
minfpg = fragsperinode * INOPB(&sblock);
if (minfpg > sblock.fs_size)
minfpg = sblock.fs_size;
sblock.fs_ipg = INOPB(&sblock);
sblock.fs_fpg = roundup(sblock.fs_iblkno +
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
if (sblock.fs_fpg < minfpg)
sblock.fs_fpg = minfpg;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
sblock.fs_fpg = roundup(sblock.fs_iblkno +
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
if (sblock.fs_fpg < minfpg)
sblock.fs_fpg = minfpg;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
break;
density -= sblock.fs_fsize;
}
if (density != origdensity)
printf("density reduced from %d to %d\n", origdensity, density);
 
if (maxblkspercg <= 0 || maxblkspercg >= fssize)
maxblkspercg = fssize - 1;
/*
* Start packing more blocks into the cylinder group until
* it cannot grow any larger, the number of cylinder groups
* drops below 1, or we reach the size requested.
*/
for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) {
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
if (sblock.fs_size / sblock.fs_fpg < 1)
break;
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
continue;
if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize)
break;
sblock.fs_fpg -= sblock.fs_frag;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
break;
}
/*
* Check to be sure that the last cylinder group has enough blocks
* to be viable. If it is too small, reduce the number of blocks
* per cylinder group which will have the effect of moving more
* blocks into the last cylinder group.
*/
optimalfpg = sblock.fs_fpg;
for (;;) {
sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg);
lastminfpg = roundup(sblock.fs_iblkno +
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
if (sblock.fs_size < lastminfpg) {
printf("Filesystem size %lld < minimum size of %d\n",
(long long)sblock.fs_size, lastminfpg);
exit(28);
}
if (sblock.fs_size % sblock.fs_fpg >= lastminfpg ||
sblock.fs_size % sblock.fs_fpg == 0)
break;
sblock.fs_fpg -= sblock.fs_frag;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
}
if (optimalfpg != sblock.fs_fpg)
printf("Reduced frags per cylinder group from %d to %d %s\n",
optimalfpg, sblock.fs_fpg, "to enlarge last cyl group");
sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
if (Oflag <= 1) {
sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf;
sblock.fs_old_nsect = sblock.fs_old_spc;
sblock.fs_old_npsect = sblock.fs_old_spc;
sblock.fs_old_ncyl = sblock.fs_ncg;
}
 
/*
* fill in remaining fields of the super block
*/
sblock.fs_csaddr = cgdmin(&sblock, 0);
sblock.fs_cssize =
fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
 
/*
* Setup memory for temporary in-core cylgroup summaries.
* Cribbed from ffs_mountfs().
*/
size = sblock.fs_cssize;
blks = howmany(size, sblock.fs_fsize);
if (sblock.fs_contigsumsize > 0)
size += sblock.fs_ncg * sizeof(int32_t);
if ((space = (char *)calloc(1, size)) == NULL)
err(1, "memory allocation error for cg summaries");
sblock.fs_csp = space;
space = (char *)space + sblock.fs_cssize;
if (sblock.fs_contigsumsize > 0) {
int32_t *lp;
 
sblock.fs_maxcluster = lp = space;
for (i = 0; i < sblock.fs_ncg; i++)
*lp++ = sblock.fs_contigsumsize;
}
 
sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
if (sblock.fs_sbsize > SBLOCKSIZE)
sblock.fs_sbsize = SBLOCKSIZE;
sblock.fs_minfree = minfree;
sblock.fs_maxcontig = maxcontig;
sblock.fs_maxbpg = maxbpg;
sblock.fs_optim = opt;
sblock.fs_cgrotor = 0;
sblock.fs_pendingblocks = 0;
sblock.fs_pendinginodes = 0;
sblock.fs_cstotal.cs_ndir = 0;
sblock.fs_cstotal.cs_nbfree = 0;
sblock.fs_cstotal.cs_nifree = 0;
sblock.fs_cstotal.cs_nffree = 0;
sblock.fs_fmod = 0;
sblock.fs_ronly = 0;
sblock.fs_state = 0;
sblock.fs_clean = FS_ISCLEAN;
sblock.fs_ronly = 0;
sblock.fs_id[0] = start_time.tv_sec;
sblock.fs_id[1] = random();
sblock.fs_fsmnt[0] = '\0';
csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize);
sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno -
sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno);
sblock.fs_cstotal.cs_nbfree =
fragstoblks(&sblock, sblock.fs_dsize) -
howmany(csfrags, sblock.fs_frag);
sblock.fs_cstotal.cs_nffree =
fragnum(&sblock, sblock.fs_size) +
(fragnum(&sblock, csfrags) > 0 ?
sblock.fs_frag - fragnum(&sblock, csfrags) : 0);
sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO;
sblock.fs_cstotal.cs_ndir = 0;
sblock.fs_dsize -= csfrags;
sblock.fs_time = start_time.tv_sec;
if (Oflag <= 1) {
sblock.fs_old_time = start_time.tv_sec;
sblock.fs_old_dsize = sblock.fs_dsize;
sblock.fs_old_csaddr = sblock.fs_csaddr;
sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
}
/*
* Dump out summary information about file system.
*/
#define B2MBFACTOR (1 / (1024.0 * 1024.0))
printf("%s: %.1fMB (%lld sectors) block size %d, "
"fragment size %d\n",
fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
(long long)fsbtodb(&sblock, sblock.fs_size),
sblock.fs_bsize, sblock.fs_fsize);
printf("\tusing %d cylinder groups of %.2fMB, %d blks, "
"%d inodes.\n",
sblock.fs_ncg,
(float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg);
#undef B2MBFACTOR
/*
* Now determine how wide each column will be, and calculate how
* many columns will fit in a 76 char line. 76 is the width of the
* subwindows in sysinst.
*/
printcolwidth = count_digits(
fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1)));
nprintcols = 76 / (printcolwidth + 2);
 
/*
* allocate space for superblock, cylinder group map, and
* two sets of inode blocks.
*/
if (sblock.fs_bsize < SBLOCKSIZE)
iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize;
else
iobufsize = 4 * sblock.fs_bsize;
if ((iobuf = malloc(iobufsize)) == 0) {
printf("Cannot allocate I/O buffer\n");
exit(38);
}
memset(iobuf, 0, iobufsize);
/*
* Make a copy of the superblock into the buffer that we will be
* writing out in each cylinder group.
*/
memcpy(writebuf, &sblock, sbsize);
if (fsopts->needswap)
ffs_sb_swap(&sblock, (struct fs*)writebuf);
memcpy(iobuf, writebuf, SBLOCKSIZE);
 
printf("super-block backups (for fsck -b #) at:");
for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
initcg(cylno, start_time.tv_sec, fsopts);
if (cylno % nprintcols == 0)
printf("\n");
printf(" %*lld,", printcolwidth,
(long long)fsbtodb(&sblock, cgsblock(&sblock, cylno)));
fflush(stdout);
}
printf("\n");
 
/*
* Now construct the initial file system,
* then write out the super-block.
*/
sblock.fs_time = start_time.tv_sec;
if (Oflag <= 1) {
sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
}
if (fsopts->needswap)
sblock.fs_flags |= FS_SWAPPED;
ffs_write_superblock(&sblock, fsopts);
return (&sblock);
}
 
/*
* Write out the superblock and its duplicates,
* and the cylinder group summaries
*/
void
ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts)
{
int cylno, size, blks, i, saveflag;
void *space;
char *wrbuf;
 
saveflag = fs->fs_flags & FS_INTERNAL;
fs->fs_flags &= ~FS_INTERNAL;
 
memcpy(writebuf, &sblock, sbsize);
if (fsopts->needswap)
ffs_sb_swap(fs, (struct fs*)writebuf);
ffs_wtfs(fs->fs_sblockloc / sectorsize, sbsize, writebuf, fsopts);
 
/* Write out the duplicate super blocks */
for (cylno = 0; cylno < fs->fs_ncg; cylno++)
ffs_wtfs(fsbtodb(fs, cgsblock(fs, cylno)),
sbsize, writebuf, fsopts);
 
/* Write out the cylinder group summaries */
size = fs->fs_cssize;
blks = howmany(size, fs->fs_fsize);
space = (void *)fs->fs_csp;
if ((wrbuf = malloc(size)) == NULL)
err(1, "ffs_write_superblock: malloc %d", size);
for (i = 0; i < blks; i+= fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
size = (blks - i) * fs->fs_fsize;
if (fsopts->needswap)
ffs_csum_swap((struct csum *)space,
(struct csum *)wrbuf, size);
else
memcpy(wrbuf, space, (u_int)size);
ffs_wtfs(fsbtodb(fs, fs->fs_csaddr + i), size, wrbuf, fsopts);
space = (char *)space + size;
}
free(wrbuf);
fs->fs_flags |= saveflag;
}
 
/*
* Initialize a cylinder group.
*/
static void
initcg(int cylno, time_t utime, const fsinfo_t *fsopts)
{
daddr_t cbase, dmax;
int32_t i, j, d, dlower, dupper, blkno;
struct ufs1_dinode *dp1;
struct ufs2_dinode *dp2;
int start;
 
/*
* Determine block bounds for cylinder group.
* Allow space for super block summary information in first
* cylinder group.
*/
cbase = cgbase(&sblock, cylno);
dmax = cbase + sblock.fs_fpg;
if (dmax > sblock.fs_size)
dmax = sblock.fs_size;
dlower = cgsblock(&sblock, cylno) - cbase;
dupper = cgdmin(&sblock, cylno) - cbase;
if (cylno == 0)
dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
memset(&acg, 0, sblock.fs_cgsize);
acg.cg_time = utime;
acg.cg_magic = CG_MAGIC;
acg.cg_cgx = cylno;
acg.cg_niblk = sblock.fs_ipg;
acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ?
sblock.fs_ipg : 2 * INOPB(&sblock);
acg.cg_ndblk = dmax - cbase;
if (sblock.fs_contigsumsize > 0)
acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift;
start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield);
if (Oflag == 2) {
acg.cg_iusedoff = start;
} else {
if (cylno == sblock.fs_ncg - 1)
acg.cg_old_ncyl = howmany(acg.cg_ndblk,
sblock.fs_fpg / sblock.fs_old_cpg);
else
acg.cg_old_ncyl = sblock.fs_old_cpg;
acg.cg_old_time = acg.cg_time;
acg.cg_time = 0;
acg.cg_old_niblk = acg.cg_niblk;
acg.cg_niblk = 0;
acg.cg_initediblk = 0;
acg.cg_old_btotoff = start;
acg.cg_old_boff = acg.cg_old_btotoff +
sblock.fs_old_cpg * sizeof(int32_t);
acg.cg_iusedoff = acg.cg_old_boff +
sblock.fs_old_cpg * sizeof(u_int16_t);
}
acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
if (sblock.fs_contigsumsize <= 0) {
acg.cg_nextfreeoff = acg.cg_freeoff +
howmany(sblock.fs_fpg, CHAR_BIT);
} else {
acg.cg_clustersumoff = acg.cg_freeoff +
howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t);
acg.cg_clustersumoff =
roundup(acg.cg_clustersumoff, sizeof(int32_t));
acg.cg_clusteroff = acg.cg_clustersumoff +
(sblock.fs_contigsumsize + 1) * sizeof(int32_t);
acg.cg_nextfreeoff = acg.cg_clusteroff +
howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
}
if (acg.cg_nextfreeoff > sblock.fs_cgsize) {
printf("Panic: cylinder group too big\n");
exit(37);
}
acg.cg_cs.cs_nifree += sblock.fs_ipg;
if (cylno == 0)
for (i = 0; i < ROOTINO; i++) {
setbit(cg_inosused(&acg, 0), i);
acg.cg_cs.cs_nifree--;
}
if (cylno > 0) {
/*
* In cylno 0, beginning space is reserved
* for boot and super blocks.
*/
for (d = 0, blkno = 0; d < dlower;) {
ffs_setblock(&sblock, cg_blksfree(&acg, 0), blkno);
if (sblock.fs_contigsumsize > 0)
setbit(cg_clustersfree(&acg, 0), blkno);
acg.cg_cs.cs_nbfree++;
d += sblock.fs_frag;
blkno++;
}
}
if ((i = (dupper & (sblock.fs_frag - 1))) != 0) {
acg.cg_frsum[sblock.fs_frag - i]++;
for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
setbit(cg_blksfree(&acg, 0), dupper);
acg.cg_cs.cs_nffree++;
}
}
for (d = dupper, blkno = dupper >> sblock.fs_fragshift;
d + sblock.fs_frag <= acg.cg_ndblk; ) {
ffs_setblock(&sblock, cg_blksfree(&acg, 0), blkno);
if (sblock.fs_contigsumsize > 0)
setbit(cg_clustersfree(&acg, 0), blkno);
acg.cg_cs.cs_nbfree++;
d += sblock.fs_frag;
blkno++;
}
if (d < acg.cg_ndblk) {
acg.cg_frsum[acg.cg_ndblk - d]++;
for (; d < acg.cg_ndblk; d++) {
setbit(cg_blksfree(&acg, 0), d);
acg.cg_cs.cs_nffree++;
}
}
if (sblock.fs_contigsumsize > 0) {
int32_t *sump = cg_clustersum(&acg, 0);
u_char *mapp = cg_clustersfree(&acg, 0);
int map = *mapp++;
int bit = 1;
int run = 0;
 
for (i = 0; i < acg.cg_nclusterblks; i++) {
if ((map & bit) != 0) {
run++;
} else if (run != 0) {
if (run > sblock.fs_contigsumsize)
run = sblock.fs_contigsumsize;
sump[run]++;
run = 0;
}
if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
bit <<= 1;
} else {
map = *mapp++;
bit = 1;
}
}
if (run != 0) {
if (run > sblock.fs_contigsumsize)
run = sblock.fs_contigsumsize;
sump[run]++;
}
}
sblock.fs_cs(&sblock, cylno) = acg.cg_cs;
/*
* Write out the duplicate super block, the cylinder group map
* and two blocks worth of inodes in a single write.
*/
start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE;
memcpy(&iobuf[start], &acg, sblock.fs_cgsize);
if (fsopts->needswap)
ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock);
start += sblock.fs_bsize;
dp1 = (struct ufs1_dinode *)(&iobuf[start]);
dp2 = (struct ufs2_dinode *)(&iobuf[start]);
for (i = 0; i < acg.cg_initediblk; i++) {
if (sblock.fs_magic == FS_UFS1_MAGIC) {
/* No need to swap, it'll stay random */
dp1->di_gen = random();
dp1++;
} else {
dp2->di_gen = random();
dp2++;
}
}
ffs_wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf,
fsopts);
/*
* For the old file system, we have to initialize all the inodes.
*/
if (Oflag <= 1) {
for (i = 2 * sblock.fs_frag;
i < sblock.fs_ipg / INOPF(&sblock);
i += sblock.fs_frag) {
dp1 = (struct ufs1_dinode *)(&iobuf[start]);
for (j = 0; j < INOPB(&sblock); j++) {
dp1->di_gen = random();
dp1++;
}
ffs_wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
sblock.fs_bsize, &iobuf[start], fsopts);
}
}
}
 
/*
* read a block from the file system
*/
void
ffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
{
int n;
off_t offset;
 
offset = bno;
offset *= fsopts->sectorsize;
if (lseek(fsopts->fd, offset, SEEK_SET) < 0)
err(1, "ffs_rdfs: seek error for sector %lld: %s\n",
(long long)bno, strerror(errno));
n = read(fsopts->fd, bf, size);
if (n == -1) {
abort();
err(1, "ffs_rdfs: read error bno %lld size %d", (long long)bno,
size);
}
else if (n != size)
errx(1, "ffs_rdfs: read error for sector %lld: %s\n",
(long long)bno, strerror(errno));
}
 
/*
* write a block to the file system
*/
void
ffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
{
int n;
off_t offset;
 
offset = bno;
offset *= fsopts->sectorsize;
if (lseek(fsopts->fd, offset, SEEK_SET) < 0)
err(1, "wtfs: seek error for sector %lld: %s\n",
(long long)bno, strerror(errno));
n = write(fsopts->fd, bf, size);
if (n == -1)
err(1, "wtfs: write error for sector %lld: %s\n",
(long long)bno, strerror(errno));
else if (n != size)
errx(1, "wtfs: write error for sector %lld: %s\n",
(long long)bno, strerror(errno));
}
 
 
/* Determine how many digits are needed to print a given integer */
static int
count_digits(int num)
{
int ndig;
 
for(ndig = 1; num > 9; num /=10, ndig++);
 
return (ndig);
}
 
static int
ilog2(int val)
{
u_int n;
 
for (n = 0; n < sizeof(n) * CHAR_BIT; n++)
if (1 << n == val)
return (n);
errx(1, "ilog2: %d is not a power of 2\n", val);
}
/disk/tools/fs-NetBSD/makefs/makefs.c
0,0 → 1,415
/* $NetBSD: makefs.c,v 1.31 2012/01/28 02:35:46 christos Exp $ */
 
/*
* Copyright (c) 2001-2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: makefs.c,v 1.31 2012/01/28 02:35:46 christos Exp $");
#endif /* !__lint */
 
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
 
#include "common.h"
#include "makefs.h"
#include "mtree.h"
 
/*
* list of supported file systems and dispatch functions
*/
typedef struct {
const char *type;
void (*prepare_options)(fsinfo_t *);
int (*parse_options)(const char *, fsinfo_t *);
void (*cleanup_options)(fsinfo_t *);
void (*make_fs)(const char *, const char *, fsnode *,
fsinfo_t *);
} fstype_t;
 
static fstype_t fstypes[] = {
{ "ffs", ffs_prep_opts, ffs_parse_opts, ffs_cleanup_opts, ffs_makefs },
{ .type = NULL },
};
 
u_int debug;
struct timespec start_time;
 
static fstype_t *get_fstype(const char *);
static void usage(void);
int main(int, char *[]);
 
static const char *progname = NULL;
 
void setprogname(const char *name) {
progname = name;
}
 
const char *getprogname(void) {
return progname;
}
 
long getValue(const char *desc, const char *val, long min, long max) {
long result;
char *endp;
 
result = strtol(val, &endp, 0);
if (*endp != '\0') {
if (strcmp(endp, "b") == 0) {
result *= 512;
} else
if (strcmp(endp, "k") == 0) {
result *= 1024;
} else
if (strcmp(endp, "m") == 0) {
result *= 1048576;
} else
if (strcmp(endp, "w") == 0) {
result *= sizeof(int);
} else {
errx(1, "%s, unknown suffix '%s'", desc, endp);
}
}
if (result < min || result > max) {
errx(1, "%s, value out of range", desc);
}
return result;
}
 
u_int nodetoino(u_int type) {
switch (type) {
case F_BLOCK:
return S_IFBLK;
case F_CHAR:
return S_IFCHR;
case F_DIR:
return S_IFDIR;
case F_FIFO:
return S_IFIFO;
case F_FILE:
return S_IFREG;
case F_LINK:
return S_IFLNK;
default:
printf("unknown type %d", type);
abort();
}
}
 
const char *inotype(u_int type) {
switch (type & S_IFMT) {
case S_IFBLK:
return "block";
case S_IFCHR:
return "char";
case S_IFDIR:
return "dir";
case S_IFIFO:
return "fifo";
case S_IFREG:
return "file";
case S_IFLNK:
return "link";
default:
return "unknown";
}
}
 
int setup_getid(const char *dir) {
return 0;
}
 
int
main(int argc, char *argv[])
{
struct timeval start;
fstype_t *fstype;
fsinfo_t fsoptions;
fsnode *root;
int ch, i, len;
char *specfile;
 
setprogname(argv[0]);
 
debug = 0;
if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL)
errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE);
 
/* set default fsoptions */
(void)memset(&fsoptions, 0, sizeof(fsoptions));
fsoptions.fd = -1;
fsoptions.sectorsize = -1;
 
if (fstype->prepare_options)
fstype->prepare_options(&fsoptions);
 
specfile = NULL;
if (gettimeofday(&start, NULL) == -1)
err(1, "Unable to get system time");
 
start_time.tv_sec = start.tv_sec;
start_time.tv_nsec = start.tv_usec * 1000;
 
while ((ch = getopt(argc, argv, "B:b:d:f:F:M:m:N:o:s:S:t:x")) != -1) {
switch (ch) {
 
case 'B':
if (strcmp(optarg, "be") == 0 ||
strcmp(optarg, "4321") == 0 ||
strcmp(optarg, "big") == 0) {
#if BYTE_ORDER == LITTLE_ENDIAN
fsoptions.needswap = 1;
#endif
} else if (strcmp(optarg, "le") == 0 ||
strcmp(optarg, "1234") == 0 ||
strcmp(optarg, "little") == 0) {
#if BYTE_ORDER == BIG_ENDIAN
fsoptions.needswap = 1;
#endif
} else {
warnx("Invalid endian `%s'.", optarg);
usage();
}
break;
 
case 'b':
len = strlen(optarg) - 1;
if (optarg[len] == '%') {
optarg[len] = '\0';
fsoptions.freeblockpc =
getValue("free block percentage",
optarg, 0, 99);
} else {
fsoptions.freeblocks =
getValue("free blocks",
optarg, 0, LONG_MAX);
}
break;
 
case 'd':
debug = strtoll(optarg, NULL, 0);
break;
 
case 'f':
len = strlen(optarg) - 1;
if (optarg[len] == '%') {
optarg[len] = '\0';
fsoptions.freefilepc =
getValue("free file percentage",
optarg, 0, 99);
} else {
fsoptions.freefiles =
getValue("free files",
optarg, 0, LONG_MAX);
}
break;
 
case 'F':
specfile = optarg;
break;
 
case 'M':
fsoptions.minsize =
getValue("minimum size", optarg, 1L, LONG_MAX);
break;
 
case 'N':
if (! setup_getid(optarg))
errx(1,
"Unable to use user and group databases in `%s'",
optarg);
break;
 
case 'm':
fsoptions.maxsize =
getValue("maximum size", optarg, 1L, LONG_MAX);
break;
case 'o':
{
char *p;
 
while ((p = strsep(&optarg, ",")) != NULL) {
if (*p == '\0')
errx(1, "Empty option");
if (! fstype->parse_options(p, &fsoptions))
usage();
}
break;
}
 
case 's':
fsoptions.minsize = fsoptions.maxsize =
getValue("size", optarg, 1L, LONG_MAX);
break;
 
case 'S':
fsoptions.sectorsize =
(int)getValue("sector size", optarg,
1LL, INT_MAX);
break;
 
case 't':
/* Check current one and cleanup if necessary. */
if (fstype->cleanup_options)
fstype->cleanup_options(&fsoptions);
fsoptions.fs_specific = NULL;
if ((fstype = get_fstype(optarg)) == NULL)
errx(1, "Unknown fs type `%s'.", optarg);
fstype->prepare_options(&fsoptions);
break;
 
case 'x':
fsoptions.onlyspec = 1;
break;
 
case '?':
default:
usage();
/* NOTREACHED */
 
}
}
if (debug) {
printf("debug mask: 0x%08x\n", debug);
printf("start time: %ld.%ld, %s",
(long)start_time.tv_sec, (long)start_time.tv_nsec,
ctime(&start_time.tv_sec));
}
argc -= optind;
argv += optind;
 
if (argc < 2)
usage();
 
/* -x must be accompanied by -F */
if (fsoptions.onlyspec != 0 && specfile == NULL)
errx(1, "-x requires -F mtree-specfile.");
 
/* walk the tree */
TIMER_START(start);
root = walk_dir(argv[1], ".", NULL, NULL);
TIMER_RESULTS(start, "walk_dir");
 
/* append extra directory */
for (i = 2; i < argc; i++) {
struct stat sb;
if (stat(argv[i], &sb) == -1)
err(1, "Can't stat `%s'", argv[i]);
if (!S_ISDIR(sb.st_mode))
errx(1, "%s: not a directory", argv[i]);
TIMER_START(start);
root = walk_dir(argv[i], ".", NULL, root);
TIMER_RESULTS(start, "walk_dir2");
}
 
if (specfile) { /* apply a specfile */
TIMER_START(start);
apply_specfile(specfile, argv[1], root, fsoptions.onlyspec);
TIMER_RESULTS(start, "apply_specfile");
}
 
if (debug & DEBUG_DUMP_FSNODES) {
printf("\nparent: %s\n", argv[1]);
dump_fsnodes(root);
putchar('\n');
}
 
/* build the file system */
TIMER_START(start);
fstype->make_fs(argv[0], argv[1], root, &fsoptions);
TIMER_RESULTS(start, "make_fs");
 
free_fsnodes(root);
 
exit(0);
/* NOTREACHED */
}
 
 
int
set_option(option_t *options, const char *var, const char *val)
{
int i;
 
for (i = 0; options[i].name != NULL; i++) {
if (strcmp(options[i].name, var) != 0)
continue;
*options[i].value = (int)getValue(options[i].desc, val,
options[i].minimum, options[i].maximum);
return (1);
}
warnx("Unknown option `%s'", var);
return (0);
}
 
 
static fstype_t *
get_fstype(const char *type)
{
int i;
for (i = 0; fstypes[i].type != NULL; i++)
if (strcmp(fstypes[i].type, type) == 0)
return (&fstypes[i]);
return (NULL);
}
 
static void
usage(void)
{
const char *prog;
 
prog = getprogname();
fprintf(stderr,
"usage: %s [-x] [-B endian] [-b free-blocks] [-d debug-mask]\n"
"\t[-F mtree-specfile] [-f free-files] [-M minimum-size]\n"
"\t[-m maximum-size] [-N userdb-dir] [-o fs-options] [-S sector-size]\n"
"\t[-s image-size] [-t fs-type] image-file directory [extra-directory ...]\n",
prog);
exit(1);
}
/disk/tools/fs-NetBSD/makefs/dinode.h
0,0 → 1,180
/* $NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp $ */
 
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dinode.h 8.9 (Berkeley) 3/29/95
*/
 
/*
* NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
*/
 
#ifndef _UFS_UFS_DINODE_H_
#define _UFS_UFS_DINODE_H_
 
/*
* The root inode is the root of the file system. Inode 0 can't be used for
* normal purposes and historically bad blocks were linked to inode 1, thus
* the root inode is 2. (Inode 1 is no longer used for this purpose, however
* numerous dump tapes make this assumption, so we are stuck with it).
*/
#define ROOTINO ((ino_t)2)
 
/*
* The Whiteout inode# is a dummy non-zero inode number which will
* never be allocated to a real file. It is used as a place holder
* in the directory entry which has been tagged as a DT_W entry.
* See the comments about ROOTINO above.
*/
#define WINO ((ino_t)1)
 
/*
* A dinode contains all the meta-data associated with a UFS file.
* This structure defines the on-disk format of a dinode. Since
* this structure describes an on-disk structure, all its fields
* are defined by types with precise widths.
*/
 
#define NXADDR 2
#define NDADDR 12 /* Direct addresses in inode. */
#define NIADDR 3 /* Indirect addresses in inode. */
 
struct ufs1_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
union {
u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */
u_int32_t inumber; /* 4: Lfs: inode number. */
} di_u;
u_int64_t di_size; /* 8: File byte count. */
int32_t di_atime; /* 16: Last access time. */
int32_t di_atimensec; /* 20: Last access time. */
int32_t di_mtime; /* 24: Last modified time. */
int32_t di_mtimensec; /* 28: Last modified time. */
int32_t di_ctime; /* 32: Last inode change time. */
int32_t di_ctimensec; /* 36: Last inode change time. */
int32_t di_db[NDADDR]; /* 40: Direct disk blocks. */
int32_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
u_int32_t di_flags; /* 100: Status flags (chflags). */
u_int32_t di_blocks; /* 104: Blocks actually held. */
int32_t di_gen; /* 108: Generation number. */
u_int32_t di_uid; /* 112: File owner. */
u_int32_t di_gid; /* 116: File group. */
u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */
};
 
struct ufs2_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
u_int32_t di_uid; /* 4: File owner. */
u_int32_t di_gid; /* 8: File group. */
u_int32_t di_blksize; /* 12: Inode blocksize. */
u_int64_t di_size; /* 16: File byte count. */
u_int64_t di_blocks; /* 24: Bytes actually held. */
int64_t di_atime; /* 32: Last access time. */
int64_t di_mtime; /* 40: Last modified time. */
int64_t di_ctime; /* 48: Last inode change time. */
int64_t di_birthtime; /* 56: Inode creation time. */
int32_t di_mtimensec; /* 64: Last modified time. */
int32_t di_atimensec; /* 68: Last access time. */
int32_t di_ctimensec; /* 72: Last inode change time. */
int32_t di_birthnsec; /* 76: Inode creation time. */
int32_t di_gen; /* 80: Generation number. */
u_int32_t di_kernflags; /* 84: Kernel flags. */
u_int32_t di_flags; /* 88: Status flags (chflags). */
int32_t di_extsize; /* 92: External attributes block. */
int64_t di_extb[NXADDR];/* 96: External attributes block. */
int64_t di_db[NDADDR]; /* 112: Direct disk blocks. */
int64_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */
int64_t di_spare[2]; /* 240: Reserved; currently unused */
};
 
/*
* The di_db fields may be overlaid with other information for
* file types that do not have associated disk storage. Block
* and character devices overlay the first data block with their
* dev_t value. Short symbolic links place their path in the
* di_db area.
*/
#define di_inumber di_u.inumber
#define di_ogid di_u.oldids[1]
#define di_ouid di_u.oldids[0]
#define di_rdev di_db[0]
#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(int32_t))
#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(int64_t))
 
#define MAXSYMLINKLEN(ip) \
((ip)->i_ump->um_fstype == UFS1) ? \
MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2
 
/* NeXT used to keep short symlinks in the inode even when using
* FS_42INODEFMT. In that case fs->fs_maxsymlinklen is probably -1,
* but short symlinks were stored in inodes shorter than this:
*/
#define APPLEUFS_MAXSYMLINKLEN 60
 
/* File permissions. */
#define IEXEC 0000100 /* Executable. */
#define IWRITE 0000200 /* Writable. */
#define IREAD 0000400 /* Readable. */
#define ISVTX 0001000 /* Sticky bit. */
#define ISGID 0002000 /* Set-gid. */
#define ISUID 0004000 /* Set-uid. */
 
/* File types. */
#define IFMT 0170000 /* Mask of file type. */
#define IFIFO 0010000 /* Named pipe (fifo). */
#define IFCHR 0020000 /* Character device. */
#define IFDIR 0040000 /* Directory file. */
#define IFBLK 0060000 /* Block device. */
#define IFREG 0100000 /* Regular file. */
#define IFLNK 0120000 /* Symbolic link. */
#define IFSOCK 0140000 /* UNIX domain socket. */
#define IFWHT 0160000 /* Whiteout. */
 
/* Size of the on-disk inode. */
#define DINODE1_SIZE (sizeof(struct ufs1_dinode)) /* 128 */
#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
 
#endif /* !_UFS_UFS_DINODE_H_ */
/disk/tools/fs-NetBSD/makefs/ffs_extern.h
0,0 → 1,76
/* $NetBSD: ffs_extern.h,v 1.6 2003/08/07 11:25:33 agc Exp $ */
/* From: NetBSD: ffs_extern.h,v 1.19 2001/08/17 02:18:48 lukem Exp */
 
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95
*/
 
#include "buf.h"
 
/*
* Structure used to pass around logical block paths generated by
* ufs_getlbns and used by truncate and bmap code.
*/
struct indir {
daddr_t in_lbn; /* Logical block number. */
int in_off; /* Offset in buffer. */
int in_exists; /* Flag if the block exists. */
};
 
/* ffs.c */
void panic(const char *, ...)
__attribute__((__noreturn__,__format__(__printf__,1,2)));
 
/* ffs_alloc.c */
int ffs_alloc(struct inode *, daddr_t, daddr_t, int, daddr_t *);
daddr_t ffs_blkpref_ufs1(struct inode *, daddr_t, int, int32_t *);
daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int64_t *);
void ffs_blkfree(struct inode *, daddr_t, long);
void ffs_clusteracct(struct fs *, struct cg *, int32_t, int);
 
/* ffs_balloc.c */
int ffs_balloc(struct inode *, off_t, int, struct buf **);
 
/* ffs_bswap.c */
void ffs_sb_swap(struct fs*, struct fs *);
void ffs_dinode1_swap(struct ufs1_dinode *, struct ufs1_dinode *);
void ffs_dinode2_swap(struct ufs2_dinode *, struct ufs2_dinode *);
void ffs_csum_swap(struct csum *, struct csum *, int);
void ffs_cg_swap(struct cg *, struct cg *, struct fs *);
 
/* ffs_subr.c */
void ffs_fragacct(struct fs *, int, int32_t[], int, int);
int ffs_isblock(struct fs *, u_char *, int32_t);
int ffs_isfreeblock(struct fs *, u_char *, int32_t);
void ffs_clrblock(struct fs *, u_char *, int32_t);
void ffs_setblock(struct fs *, u_char *, int32_t);
 
/* ufs_bmap.c */
int ufs_getlbns(struct inode *, daddr_t, struct indir *, int *);
/disk/tools/fs-NetBSD/makefs/ffs_tables.c
0,0 → 1,146
/* $NetBSD: ffs_tables.c,v 1.9 2005/12/11 12:25:25 christos Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_tables.c 8.1 (Berkeley) 6/11/93
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__KERNEL_RCSID) && !defined(__lint)
__KERNEL_RCSID(0, "$NetBSD: ffs_tables.c,v 1.9 2005/12/11 12:25:25 christos Exp $");
#endif
 
#include <sys/param.h>
 
#include "common.h"
#include "fs.h"
 
/*
* Bit patterns for identifying fragments in the block map
* used as ((map & around) == inside)
*/
const int around[9] = {
0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
};
const int inside[9] = {
0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
};
 
/*
* Given a block map bit pattern, the frag tables tell whether a
* particular size fragment is available.
*
* used as:
* if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] {
* at least one fragment of the indicated size is available
* }
*
* These tables are used by the scanc instruction on the VAX to
* quickly find an appropriate fragment.
*/
const u_char fragtbl124[256] = {
0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e,
0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a,
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e,
0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae,
0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce,
0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a,
};
 
const u_char fragtbl8[256] = {
0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04,
0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12,
0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c,
0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c,
0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
};
 
/*
* The actual fragtbl array.
*/
const u_char * const fragtbl[MAXFRAG + 1] = {
0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8,
};
/disk/tools/fs-NetBSD/makefs/ffs_subr.c
0,0 → 1,377
/* $NetBSD: ffs_subr.c,v 1.47 2011/08/14 12:37:09 christos Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__KERNEL_RCSID) && !defined(__lint)
__KERNEL_RCSID(0, "$NetBSD: ffs_subr.c,v 1.47 2011/08/14 12:37:09 christos Exp $");
#endif
 
#include <sys/param.h>
 
#include "common.h"
 
/* in ffs_tables.c */
extern const int inside[], around[];
extern const u_char * const fragtbl[];
 
#ifndef _KERNEL
#define FFS_EI /* always include byteswapped filesystems support */
#endif
#include "fs.h"
#include "dinode.h"
#include "ufs_inode.h"
#include "ffs_extern.h"
#include "ufs_bswap.h"
 
#ifndef _KERNEL
#include "dinode.h"
void panic(const char *, ...)
__attribute__((__noreturn__,__format__(__printf__,1,2)));
 
#else /* _KERNEL */
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/inttypes.h>
#include <sys/pool.h>
#include <sys/fstrans.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
 
/*
* Load up the contents of an inode and copy the appropriate pieces
* to the incore copy.
*/
void
ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
{
struct ufs1_dinode *dp1;
struct ufs2_dinode *dp2;
 
if (ip->i_ump->um_fstype == UFS1) {
dp1 = (struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino);
#ifdef FFS_EI
if (UFS_FSNEEDSWAP(fs))
ffs_dinode1_swap(dp1, ip->i_din.ffs1_din);
else
#endif
*ip->i_din.ffs1_din = *dp1;
 
ip->i_mode = ip->i_ffs1_mode;
ip->i_nlink = ip->i_ffs1_nlink;
ip->i_size = ip->i_ffs1_size;
ip->i_flags = ip->i_ffs1_flags;
ip->i_gen = ip->i_ffs1_gen;
ip->i_uid = ip->i_ffs1_uid;
ip->i_gid = ip->i_ffs1_gid;
} else {
dp2 = (struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino);
#ifdef FFS_EI
if (UFS_FSNEEDSWAP(fs))
ffs_dinode2_swap(dp2, ip->i_din.ffs2_din);
else
#endif
*ip->i_din.ffs2_din = *dp2;
 
ip->i_mode = ip->i_ffs2_mode;
ip->i_nlink = ip->i_ffs2_nlink;
ip->i_size = ip->i_ffs2_size;
ip->i_flags = ip->i_ffs2_flags;
ip->i_gen = ip->i_ffs2_gen;
ip->i_uid = ip->i_ffs2_uid;
ip->i_gid = ip->i_ffs2_gid;
}
}
 
int
ffs_getblk(struct vnode *vp, daddr_t lblkno, daddr_t blkno, int size,
bool clearbuf, buf_t **bpp)
{
int error = 0;
 
KASSERT(blkno >= 0 || blkno == FFS_NOBLK);
 
if ((*bpp = getblk(vp, lblkno, size, 0, 0)) == NULL)
return ENOMEM;
if (blkno != FFS_NOBLK)
(*bpp)->b_blkno = blkno;
if (clearbuf)
clrbuf(*bpp);
if ((*bpp)->b_blkno >= 0 && (error = fscow_run(*bpp, false)) != 0)
brelse(*bpp, BC_INVAL);
return error;
}
 
#endif /* _KERNEL */
 
/*
* Update the frsum fields to reflect addition or deletion
* of some frags.
*/
void
ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt,
int needswap)
{
int inblk;
int field, subfield;
int siz, pos;
 
inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
fragmap <<= 1;
for (siz = 1; siz < fs->fs_frag; siz++) {
if ((inblk & (1 << (siz + (fs->fs_frag & (NBBY - 1))))) == 0)
continue;
field = around[siz];
subfield = inside[siz];
for (pos = siz; pos <= fs->fs_frag; pos++) {
if ((fragmap & field) == subfield) {
fraglist[siz] = ufs_rw32(
ufs_rw32(fraglist[siz], needswap) + cnt,
needswap);
pos += siz;
field <<= siz;
subfield <<= siz;
}
field <<= 1;
subfield <<= 1;
}
}
}
 
/*
* block operations
*
* check if a block is available
* returns true if all the correponding bits in the free map are 1
* returns false if any corresponding bit in the free map is 0
*/
int
ffs_isblock(struct fs *fs, u_char *cp, int32_t h)
{
u_char mask;
 
switch ((int)fs->fs_fragshift) {
case 3:
return (cp[h] == 0xff);
case 2:
mask = 0x0f << ((h & 0x1) << 2);
return ((cp[h >> 1] & mask) == mask);
case 1:
mask = 0x03 << ((h & 0x3) << 1);
return ((cp[h >> 2] & mask) == mask);
case 0:
mask = 0x01 << (h & 0x7);
return ((cp[h >> 3] & mask) == mask);
default:
panic("ffs_isblock: unknown fs_fragshift %d",
(int)fs->fs_fragshift);
}
}
 
/*
* check if a block is completely allocated
* returns true if all the corresponding bits in the free map are 0
* returns false if any corresponding bit in the free map is 1
*/
int
ffs_isfreeblock(struct fs *fs, u_char *cp, int32_t h)
{
 
switch ((int)fs->fs_fragshift) {
case 3:
return (cp[h] == 0);
case 2:
return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
case 1:
return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
case 0:
return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
default:
panic("ffs_isfreeblock: unknown fs_fragshift %d",
(int)fs->fs_fragshift);
}
}
 
/*
* take a block out of the map
*/
void
ffs_clrblock(struct fs *fs, u_char *cp, int32_t h)
{
 
switch ((int)fs->fs_fragshift) {
case 3:
cp[h] = 0;
return;
case 2:
cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
return;
case 1:
cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
return;
case 0:
cp[h >> 3] &= ~(0x01 << (h & 0x7));
return;
default:
panic("ffs_clrblock: unknown fs_fragshift %d",
(int)fs->fs_fragshift);
}
}
 
/*
* put a block into the map
*/
void
ffs_setblock(struct fs *fs, u_char *cp, int32_t h)
{
 
switch ((int)fs->fs_fragshift) {
case 3:
cp[h] = 0xff;
return;
case 2:
cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
return;
case 1:
cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
return;
case 0:
cp[h >> 3] |= (0x01 << (h & 0x7));
return;
default:
panic("ffs_setblock: unknown fs_fragshift %d",
(int)fs->fs_fragshift);
}
}
 
/*
* Update the cluster map because of an allocation or free.
*
* Cnt == 1 means free; cnt == -1 means allocating.
*/
void
ffs_clusteracct(struct fs *fs, struct cg *cgp, int32_t blkno, int cnt)
{
int32_t *sump;
int32_t *lp;
u_char *freemapp, *mapp;
int i, start, end, forw, back, map, bit;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
 
/* KASSERT(mutex_owned(&ump->um_lock)); */
 
if (fs->fs_contigsumsize <= 0)
return;
freemapp = cg_clustersfree(cgp, needswap);
sump = cg_clustersum(cgp, needswap);
/*
* Allocate or clear the actual block.
*/
if (cnt > 0)
setbit(freemapp, blkno);
else
clrbit(freemapp, blkno);
/*
* Find the size of the cluster going forward.
*/
start = blkno + 1;
end = start + fs->fs_contigsumsize;
if ((uint32_t)end >= ufs_rw32(cgp->cg_nclusterblks, needswap))
end = ufs_rw32(cgp->cg_nclusterblks, needswap);
mapp = &freemapp[start / NBBY];
map = *mapp++;
bit = 1 << (start % NBBY);
for (i = start; i < end; i++) {
if ((map & bit) == 0)
break;
if ((i & (NBBY - 1)) != (NBBY - 1)) {
bit <<= 1;
} else {
map = *mapp++;
bit = 1;
}
}
forw = i - start;
/*
* Find the size of the cluster going backward.
*/
start = blkno - 1;
end = start - fs->fs_contigsumsize;
if (end < 0)
end = -1;
mapp = &freemapp[start / NBBY];
map = *mapp--;
bit = 1 << (start % NBBY);
for (i = start; i > end; i--) {
if ((map & bit) == 0)
break;
if ((i & (NBBY - 1)) != 0) {
bit >>= 1;
} else {
map = *mapp--;
bit = 1 << (NBBY - 1);
}
}
back = start - i;
/*
* Account for old cluster and the possibly new forward and
* back clusters.
*/
i = back + forw + 1;
if (i > fs->fs_contigsumsize)
i = fs->fs_contigsumsize;
ufs_add32(sump[i], cnt, needswap);
if (back > 0)
ufs_add32(sump[back], -cnt, needswap);
if (forw > 0)
ufs_add32(sump[forw], -cnt, needswap);
 
/*
* Update cluster summary information.
*/
lp = &sump[fs->fs_contigsumsize];
for (i = fs->fs_contigsumsize; i > 0; i--)
if (ufs_rw32(*lp--, needswap) > 0)
break;
#if defined(_KERNEL)
fs->fs_maxcluster[ufs_rw32(cgp->cg_cgx, needswap)] = i;
#endif
}
/disk/tools/fs-NetBSD/makefs/ffs_bswap.c
0,0 → 1,279
/* $NetBSD: ffs_bswap.c,v 1.35 2011/03/06 17:08:38 bouyer Exp $ */
 
/*
* Copyright (c) 1998 Manuel Bouyer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__KERNEL_RCSID) && !defined(__lint)
__KERNEL_RCSID(0, "$NetBSD: ffs_bswap.c,v 1.35 2011/03/06 17:08:38 bouyer Exp $");
#endif
 
#include <sys/param.h>
#if defined(_KERNEL)
#include <sys/systm.h>
#endif
 
#include "common.h"
 
#include "dinode.h"
#include "ufs_inode.h"
//#include <ufs/ufs/quota.h>
#include "ufs_bswap.h"
#include "fs.h"
#include "ffs_extern.h"
 
#if !defined(_KERNEL)
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define panic(x) printf("%s\n", (x)), abort()
#endif
 
void
ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n);
 
void
ffs_sb_swap(struct fs *o, struct fs *n)
{
size_t i;
u_int32_t *o32, *n32;
 
/*
* In order to avoid a lot of lines, as the first N fields (52)
* of the superblock up to fs_fmod are u_int32_t, we just loop
* here to convert them.
*/
o32 = (u_int32_t *)o;
n32 = (u_int32_t *)n;
for (i = 0; i < offsetof(struct fs, fs_fmod) / sizeof(u_int32_t); i++)
n32[i] = bswap32(o32[i]);
 
n->fs_swuid = bswap64(o->fs_swuid);
n->fs_cgrotor = bswap32(o->fs_cgrotor); /* Unused */
n->fs_old_cpc = bswap32(o->fs_old_cpc);
 
/* These fields overlap with a possible location for the
* historic FS_DYNAMICPOSTBLFMT postbl table, and with the
* first half of the historic FS_42POSTBLFMT postbl table.
*/
n->fs_maxbsize = bswap32(o->fs_maxbsize);
/* XXX journal */
n->fs_quota_magic = bswap32(o->fs_quota_magic);
for (i = 0; i < MAXQUOTAS; i++)
n->fs_quotafile[i] = bswap64(o->fs_quotafile[i]);
n->fs_sblockloc = bswap64(o->fs_sblockloc);
ffs_csumtotal_swap(&o->fs_cstotal, &n->fs_cstotal);
n->fs_time = bswap64(o->fs_time);
n->fs_size = bswap64(o->fs_size);
n->fs_dsize = bswap64(o->fs_dsize);
n->fs_csaddr = bswap64(o->fs_csaddr);
n->fs_pendingblocks = bswap64(o->fs_pendingblocks);
n->fs_pendinginodes = bswap32(o->fs_pendinginodes);
 
/* These fields overlap with the second half of the
* historic FS_42POSTBLFMT postbl table
*/
for (i = 0; i < FSMAXSNAP; i++)
n->fs_snapinum[i] = bswap32(o->fs_snapinum[i]);
n->fs_avgfilesize = bswap32(o->fs_avgfilesize);
n->fs_avgfpdir = bswap32(o->fs_avgfpdir);
/* fs_sparecon[28] - ignore for now */
n->fs_flags = bswap32(o->fs_flags);
n->fs_contigsumsize = bswap32(o->fs_contigsumsize);
n->fs_maxsymlinklen = bswap32(o->fs_maxsymlinklen);
n->fs_old_inodefmt = bswap32(o->fs_old_inodefmt);
n->fs_maxfilesize = bswap64(o->fs_maxfilesize);
n->fs_qbmask = bswap64(o->fs_qbmask);
n->fs_qfmask = bswap64(o->fs_qfmask);
n->fs_state = bswap32(o->fs_state);
n->fs_old_postblformat = bswap32(o->fs_old_postblformat);
n->fs_old_nrpos = bswap32(o->fs_old_nrpos);
n->fs_old_postbloff = bswap32(o->fs_old_postbloff);
n->fs_old_rotbloff = bswap32(o->fs_old_rotbloff);
 
n->fs_magic = bswap32(o->fs_magic);
}
 
void
ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n)
{
 
n->di_mode = bswap16(o->di_mode);
n->di_nlink = bswap16(o->di_nlink);
n->di_u.oldids[0] = bswap16(o->di_u.oldids[0]);
n->di_u.oldids[1] = bswap16(o->di_u.oldids[1]);
n->di_size = bswap64(o->di_size);
n->di_atime = bswap32(o->di_atime);
n->di_atimensec = bswap32(o->di_atimensec);
n->di_mtime = bswap32(o->di_mtime);
n->di_mtimensec = bswap32(o->di_mtimensec);
n->di_ctime = bswap32(o->di_ctime);
n->di_ctimensec = bswap32(o->di_ctimensec);
memcpy(n->di_db, o->di_db, (NDADDR + NIADDR) * sizeof(u_int32_t));
n->di_flags = bswap32(o->di_flags);
n->di_blocks = bswap32(o->di_blocks);
n->di_gen = bswap32(o->di_gen);
n->di_uid = bswap32(o->di_uid);
n->di_gid = bswap32(o->di_gid);
}
 
void
ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n)
{
n->di_mode = bswap16(o->di_mode);
n->di_nlink = bswap16(o->di_nlink);
n->di_uid = bswap32(o->di_uid);
n->di_gid = bswap32(o->di_gid);
n->di_blksize = bswap32(o->di_blksize);
n->di_size = bswap64(o->di_size);
n->di_blocks = bswap64(o->di_blocks);
n->di_atime = bswap64(o->di_atime);
n->di_atimensec = bswap32(o->di_atimensec);
n->di_mtime = bswap64(o->di_mtime);
n->di_mtimensec = bswap32(o->di_mtimensec);
n->di_ctime = bswap64(o->di_ctime);
n->di_ctimensec = bswap32(o->di_ctimensec);
n->di_birthtime = bswap64(o->di_birthtime);
n->di_birthnsec = bswap32(o->di_birthnsec);
n->di_gen = bswap32(o->di_gen);
n->di_kernflags = bswap32(o->di_kernflags);
n->di_flags = bswap32(o->di_flags);
n->di_extsize = bswap32(o->di_extsize);
memcpy(n->di_extb, o->di_extb, (NXADDR + NDADDR + NIADDR) * 8);
}
 
void
ffs_csum_swap(struct csum *o, struct csum *n, int size)
{
size_t i;
u_int32_t *oint, *nint;
 
oint = (u_int32_t*)o;
nint = (u_int32_t*)n;
 
for (i = 0; i < size / sizeof(u_int32_t); i++)
nint[i] = bswap32(oint[i]);
}
 
void
ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n)
{
n->cs_ndir = bswap64(o->cs_ndir);
n->cs_nbfree = bswap64(o->cs_nbfree);
n->cs_nifree = bswap64(o->cs_nifree);
n->cs_nffree = bswap64(o->cs_nffree);
}
 
/*
* Note that ffs_cg_swap may be called with o == n.
*/
void
ffs_cg_swap(struct cg *o, struct cg *n, struct fs *fs)
{
int i;
u_int32_t *n32, *o32;
u_int16_t *n16, *o16;
int32_t btotoff, boff, clustersumoff;
 
n->cg_firstfield = bswap32(o->cg_firstfield);
n->cg_magic = bswap32(o->cg_magic);
n->cg_old_time = bswap32(o->cg_old_time);
n->cg_cgx = bswap32(o->cg_cgx);
n->cg_old_ncyl = bswap16(o->cg_old_ncyl);
n->cg_old_niblk = bswap16(o->cg_old_niblk);
n->cg_ndblk = bswap32(o->cg_ndblk);
n->cg_cs.cs_ndir = bswap32(o->cg_cs.cs_ndir);
n->cg_cs.cs_nbfree = bswap32(o->cg_cs.cs_nbfree);
n->cg_cs.cs_nifree = bswap32(o->cg_cs.cs_nifree);
n->cg_cs.cs_nffree = bswap32(o->cg_cs.cs_nffree);
n->cg_rotor = bswap32(o->cg_rotor);
n->cg_frotor = bswap32(o->cg_frotor);
n->cg_irotor = bswap32(o->cg_irotor);
for (i = 0; i < MAXFRAG; i++)
n->cg_frsum[i] = bswap32(o->cg_frsum[i]);
 
if ((fs->fs_magic != FS_UFS2_MAGIC) &&
(fs->fs_old_postblformat == FS_42POSTBLFMT)) { /* old format */
struct ocg *on, *oo;
int j;
on = (struct ocg *)n;
oo = (struct ocg *)o;
 
for (i = 0; i < 32; i++) {
on->cg_btot[i] = bswap32(oo->cg_btot[i]);
for (j = 0; j < 8; j++)
on->cg_b[i][j] = bswap16(oo->cg_b[i][j]);
}
memmove(on->cg_iused, oo->cg_iused, 256);
on->cg_magic = bswap32(oo->cg_magic);
} else { /* new format */
 
n->cg_old_btotoff = bswap32(o->cg_old_btotoff);
n->cg_old_boff = bswap32(o->cg_old_boff);
n->cg_iusedoff = bswap32(o->cg_iusedoff);
n->cg_freeoff = bswap32(o->cg_freeoff);
n->cg_nextfreeoff = bswap32(o->cg_nextfreeoff);
n->cg_clustersumoff = bswap32(o->cg_clustersumoff);
n->cg_clusteroff = bswap32(o->cg_clusteroff);
n->cg_nclusterblks = bswap32(o->cg_nclusterblks);
n->cg_niblk = bswap32(o->cg_niblk);
n->cg_initediblk = bswap32(o->cg_initediblk);
n->cg_time = bswap64(o->cg_time);
 
if (n->cg_magic == CG_MAGIC) {
btotoff = n->cg_old_btotoff;
boff = n->cg_old_boff;
clustersumoff = n->cg_clustersumoff;
} else {
btotoff = bswap32(n->cg_old_btotoff);
boff = bswap32(n->cg_old_boff);
clustersumoff = bswap32(n->cg_clustersumoff);
}
 
n32 = (u_int32_t *)((u_int8_t *)n + clustersumoff);
o32 = (u_int32_t *)((u_int8_t *)o + clustersumoff);
for (i = 1; i < fs->fs_contigsumsize + 1; i++)
n32[i] = bswap32(o32[i]);
 
if (fs->fs_magic == FS_UFS2_MAGIC)
return;
 
n32 = (u_int32_t *)((u_int8_t *)n + btotoff);
o32 = (u_int32_t *)((u_int8_t *)o + btotoff);
n16 = (u_int16_t *)((u_int8_t *)n + boff);
o16 = (u_int16_t *)((u_int8_t *)o + boff);
 
for (i = 0; i < fs->fs_old_cpg; i++)
n32[i] = bswap32(o32[i]);
 
for (i = 0; i < fs->fs_old_cpg * fs->fs_old_nrpos; i++)
n16[i] = bswap16(o16[i]);
}
}
/disk/tools/fs-NetBSD/makefs/makefs.h
0,0 → 1,247
/* $NetBSD: makefs.h,v 1.24 2012/01/28 02:35:46 christos Exp $ */
 
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
 
#ifndef _MAKEFS_H
#define _MAKEFS_H
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#else
#define HAVE_STRUCT_STAT_ST_FLAGS 0
#define HAVE_STRUCT_STAT_ST_GEN 0
#define HAVE_STRUCT_STAT_ST_MTIMENSEC 0
#define HAVE_STRUCT_STATVFS_F_IOSIZE 0
#define HAVE_STRUCT_STAT_BIRTHTIME 0
#define HAVE_FSTATVFS 1
#endif
 
#include <sys/stat.h>
#include <err.h>
 
/*
* fsnode -
* a component of the tree; contains a filename, a pointer to
* fsinode, optional symlink name, and tree pointers
*
* fsinode -
* equivalent to an inode, containing target file system inode number,
* refcount (nlink), and stat buffer
*
* A tree of fsnodes looks like this:
*
* name "." "bin" "netbsd"
* type S_IFDIR S_IFDIR S_IFREG
* next > > NULL
* parent NULL NULL NULL
* child NULL v
*
* name "." "ls"
* type S_IFDIR S_IFREG
* next > NULL
* parent ^ ^ (to "bin")
* child NULL NULL
*
* Notes:
* - first always points to first entry, at current level, which
* must be "." when the tree has been built; during build it may
* not be if "." hasn't yet been found by readdir(2).
*/
 
enum fi_flags {
FI_SIZED = 1<<0, /* inode sized */
FI_ALLOCATED = 1<<1, /* fsinode->ino allocated */
FI_WRITTEN = 1<<2, /* inode written */
};
 
typedef struct {
uint32_t ino; /* inode number used on target fs */
uint32_t nlink; /* number of links to this entry */
enum fi_flags flags; /* flags used by fs specific code */
struct stat st; /* stat entry */
} fsinode;
 
typedef struct _fsnode {
struct _fsnode *parent; /* parent (NULL if root) */
struct _fsnode *child; /* child (if type == S_IFDIR) */
struct _fsnode *next; /* next */
struct _fsnode *first; /* first node of current level (".") */
uint32_t type; /* type of entry */
fsinode *inode; /* actual inode data */
char *symlink; /* symlink target */
const char *root; /* root path */
char *path; /* directory name */
char *name; /* file name */
int flags; /* misc flags */
} fsnode;
 
#define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */
 
/*
* fsinfo_t - contains various settings and parameters pertaining to
* the image, including current settings, global options, and fs
* specific options
*/
typedef struct {
/* current settings */
off_t size; /* total size */
off_t inodes; /* number of inodes */
uint32_t curinode; /* current inode */
 
/* image settings */
int fd; /* file descriptor of image */
void *superblock; /* superblock */
int onlyspec; /* only add entries in specfile */
 
 
/* global options */
off_t minsize; /* minimum size image should be */
off_t maxsize; /* maximum size image can be */
off_t freefiles; /* free file entries to leave */
int freefilepc; /* free file % */
off_t freeblocks; /* free blocks to leave */
int freeblockpc; /* free block % */
int needswap; /* non-zero if byte swapping needed */
int sectorsize; /* sector size */
 
void *fs_specific; /* File system specific additions. */
} fsinfo_t;
 
 
/*
* option_t - contains option name, description, pointer to location to store
* result, and range checks for the result. Used to simplify fs specific
* option setting
*/
typedef struct {
const char *name; /* option name */
int *value; /* where to stuff the value */
int minimum; /* minimum for value */
int maximum; /* maximum for value */
const char *desc; /* option description */
} option_t;
 
 
void apply_specfile(const char *, const char *, fsnode *, int);
void dump_fsnodes(fsnode *);
const char * inode_type(mode_t);
int set_option(option_t *, const char *, const char *);
fsnode * walk_dir(const char *, const char *, fsnode *, fsnode *);
void free_fsnodes(fsnode *);
 
void ffs_prep_opts(fsinfo_t *);
int ffs_parse_opts(const char *, fsinfo_t *);
void ffs_cleanup_opts(fsinfo_t *);
void ffs_makefs(const char *, const char *, fsnode *, fsinfo_t *);
 
void cd9660_prep_opts(fsinfo_t *);
int cd9660_parse_opts(const char *, fsinfo_t *);
void cd9660_cleanup_opts(fsinfo_t *);
void cd9660_makefs(const char *, const char *, fsnode *, fsinfo_t *);
 
void v7fs_prep_opts(fsinfo_t *);
int v7fs_parse_opts(const char *, fsinfo_t *);
void v7fs_cleanup_opts(fsinfo_t *);
void v7fs_makefs(const char *, const char *, fsnode *, fsinfo_t *);
 
extern unsigned int debug;
extern struct timespec start_time;
 
/*
* If -x is specified, we want to exclude nodes which do not appear
* in the spec file.
*/
#define FSNODE_EXCLUDE_P(opts, fsnode) \
((opts)->onlyspec != 0 && ((fsnode)->flags & FSNODE_F_HASSPEC) == 0)
 
#define DEBUG_TIME 0x00000001
/* debug bits 1..3 unused at this time */
#define DEBUG_WALK_DIR 0x00000010
#define DEBUG_WALK_DIR_NODE 0x00000020
#define DEBUG_WALK_DIR_LINKCHECK 0x00000040
#define DEBUG_DUMP_FSNODES 0x00000080
#define DEBUG_DUMP_FSNODES_VERBOSE 0x00000100
#define DEBUG_FS_PARSE_OPTS 0x00000200
#define DEBUG_FS_MAKEFS 0x00000400
#define DEBUG_FS_VALIDATE 0x00000800
#define DEBUG_FS_CREATE_IMAGE 0x00001000
#define DEBUG_FS_SIZE_DIR 0x00002000
#define DEBUG_FS_SIZE_DIR_NODE 0x00004000
#define DEBUG_FS_SIZE_DIR_ADD_DIRENT 0x00008000
#define DEBUG_FS_POPULATE 0x00010000
#define DEBUG_FS_POPULATE_DIRBUF 0x00020000
#define DEBUG_FS_POPULATE_NODE 0x00040000
#define DEBUG_FS_WRITE_FILE 0x00080000
#define DEBUG_FS_WRITE_FILE_BLOCK 0x00100000
#define DEBUG_FS_MAKE_DIRBUF 0x00200000
#define DEBUG_FS_WRITE_INODE 0x00400000
#define DEBUG_BUF_BREAD 0x00800000
#define DEBUG_BUF_BWRITE 0x01000000
#define DEBUG_BUF_GETBLK 0x02000000
#define DEBUG_APPLY_SPECFILE 0x04000000
#define DEBUG_APPLY_SPECENTRY 0x08000000
#define DEBUG_APPLY_SPECONLY 0x10000000
 
 
#define TIMER_START(x) \
if (debug & DEBUG_TIME) \
gettimeofday(&(x), NULL)
 
#define TIMER_RESULTS(x,d) \
if (debug & DEBUG_TIME) { \
struct timeval end, td; \
gettimeofday(&end, NULL); \
timersub(&end, &(x), &td); \
printf("%s took %lld.%06ld seconds\n", \
(d), (long long)td.tv_sec, \
(long)td.tv_usec); \
}
 
 
#ifndef DEFAULT_FSTYPE
#define DEFAULT_FSTYPE "ffs"
#endif
 
 
/*
* ffs specific settings
* ---------------------
*/
 
#define FFS_EI /* for opposite endian support in ffs headers */
 
 
#endif /* _MAKEFS_H */
/disk/tools/fs-NetBSD/makefs/buf.c
0,0 → 1,228
/* $NetBSD: buf.c,v 1.12 2004/06/20 22:20:18 jmc Exp $ */
 
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: buf.c,v 1.12 2004/06/20 22:20:18 jmc Exp $");
#endif /* !__lint */
 
#include <sys/param.h>
#include <sys/time.h>
 
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
#include "common.h"
#include "makefs.h"
 
#include "buf.h"
#include "fs.h"
#include "dinode.h"
#include "ufs_inode.h"
 
extern int sectorsize; /* XXX: from ffs.c & mkfs.c */
 
TAILQ_HEAD(buftailhead,buf) buftail;
 
int
bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp)
{
off_t offset;
ssize_t rv;
 
assert (fs != NULL);
assert (bpp != NULL);
 
if (debug & DEBUG_BUF_BREAD)
printf("bread: fs %p blkno %lld size %d\n",
fs, (long long)blkno, size);
*bpp = getblk(fd, fs, blkno, size);
offset = (*bpp)->b_blkno * sectorsize; /* XXX */
if (debug & DEBUG_BUF_BREAD)
printf("bread: bp %p blkno %lld offset %lld bcount %ld\n",
(*bpp), (long long)(*bpp)->b_blkno, (long long) offset,
(*bpp)->b_bcount);
if (lseek((*bpp)->b_fd, offset, SEEK_SET) == -1)
err(1, "bread: lseek %lld (%lld)",
(long long)(*bpp)->b_blkno, (long long)offset);
rv = read((*bpp)->b_fd, (*bpp)->b_data, (*bpp)->b_bcount);
if (debug & DEBUG_BUF_BREAD)
printf("bread: read %ld (%lld) returned %d\n",
(*bpp)->b_bcount, (long long)offset, (int)rv);
if (rv == -1) /* read error */
err(1, "bread: read %ld (%lld) returned %d",
(*bpp)->b_bcount, (long long)offset, (int)rv);
else if (rv != (*bpp)->b_bcount) /* short read */
err(1, "bread: read %ld (%lld) returned %d",
(*bpp)->b_bcount, (long long)offset, (int)rv);
else
return (0);
}
 
void
brelse(struct buf *bp)
{
 
assert (bp != NULL);
assert (bp->b_data != NULL);
 
if (bp->b_lblkno < 0) {
/*
* XXX don't remove any buffers with negative logical block
* numbers (lblkno), so that we retain the mapping
* of negative lblkno -> real blkno that ffs_balloc()
* sets up.
*
* if we instead released these buffers, and implemented
* ufs_strategy() (and ufs_bmaparray()) and called those
* from bread() and bwrite() to convert the lblkno to
* a real blkno, we'd add a lot more code & complexity
* and reading off disk, for little gain, because this
* simple hack works for our purpose.
*/
bp->b_bcount = 0;
return;
}
TAILQ_REMOVE(&buftail, bp, b_tailq);
free(bp->b_data);
free(bp);
}
 
int
bwrite(struct buf *bp)
{
off_t offset;
ssize_t rv;
 
assert (bp != NULL);
offset = bp->b_blkno * sectorsize; /* XXX */
if (debug & DEBUG_BUF_BWRITE)
printf("bwrite: bp %p blkno %lld offset %lld bcount %ld\n",
bp, (long long)bp->b_blkno, (long long) offset,
bp->b_bcount);
if (lseek(bp->b_fd, offset, SEEK_SET) == -1)
return (errno);
rv = write(bp->b_fd, bp->b_data, bp->b_bcount);
if (debug & DEBUG_BUF_BWRITE)
printf("bwrite: write %ld (offset %lld) returned %lld\n",
bp->b_bcount, (long long)offset, (long long)rv);
if (rv == bp->b_bcount)
return (0);
else if (rv == -1) /* write error */
return (errno);
else /* short write ? */
return (EAGAIN);
}
 
void
bcleanup(void)
{
struct buf *bp;
 
/*
* XXX this really shouldn't be necessary, but i'm curious to
* know why there's still some buffers lying around that
* aren't brelse()d
*/
if (TAILQ_EMPTY(&buftail))
return;
 
printf("bcleanup: unflushed buffers:\n");
TAILQ_FOREACH(bp, &buftail, b_tailq) {
printf("\tlblkno %10lld blkno %10lld count %6ld bufsize %6ld\n",
(long long)bp->b_lblkno, (long long)bp->b_blkno,
bp->b_bcount, bp->b_bufsize);
}
printf("bcleanup: done\n");
}
 
struct buf *
getblk(int fd, struct fs *fs, daddr_t blkno, int size)
{
static int buftailinitted;
struct buf *bp;
void *n;
 
assert (fs != NULL);
if (debug & DEBUG_BUF_GETBLK)
printf("getblk: fs %p blkno %lld size %d\n", fs,
(long long)blkno, size);
 
bp = NULL;
if (!buftailinitted) {
if (debug & DEBUG_BUF_GETBLK)
printf("getblk: initialising tailq\n");
TAILQ_INIT(&buftail);
buftailinitted = 1;
} else {
TAILQ_FOREACH(bp, &buftail, b_tailq) {
if (bp->b_lblkno != blkno)
continue;
break;
}
}
if (bp == NULL) {
if ((bp = calloc(1, sizeof(struct buf))) == NULL)
err(1, "getblk: calloc");
bp->b_bufsize = 0;
bp->b_blkno = bp->b_lblkno = blkno;
bp->b_fd = fd;
bp->b_fs = fs;
bp->b_data = NULL;
TAILQ_INSERT_HEAD(&buftail, bp, b_tailq);
}
bp->b_bcount = size;
if (bp->b_data == NULL || bp->b_bcount > bp->b_bufsize) {
n = realloc(bp->b_data, size);
if (n == NULL)
err(1, "getblk: realloc b_data %ld", bp->b_bcount);
bp->b_data = n;
bp->b_bufsize = size;
}
 
return (bp);
}
/disk/tools/fs-NetBSD/makefs/newfs_extern.h
0,0 → 1,34
/* $NetBSD: newfs_extern.h,v 1.3 2009/10/21 01:07:47 snj Exp $ */
/* From: NetBSD: extern.h,v 1.3 2000/12/01 12:03:27 simonb Exp $ */
 
/*
* Copyright (c) 1997 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/* prototypes */
struct fs *ffs_mkfs(const char *, const fsinfo_t *);
void ffs_write_superblock(struct fs *, const fsinfo_t *);
void ffs_rdfs(daddr_t, int, void *, const fsinfo_t *);
void ffs_wtfs(daddr_t, int, void *, const fsinfo_t *);
 
#define FFS_MAXBSIZE 65536
/disk/tools/fs-NetBSD/makefs/README
0,0 → 1,26
File Calling Hierarchy
----------------------
 
makefs
walk
ffs
 
ffs
mkfs
ffs_balloc
 
mkfs
ffs_bswap
ffs_subr
 
ffs_balloc
ffs_alloc
ufs_bmap
buf
 
ffs_alloc
ffs_subr
ffs_tables
 
ffs_subr
ffs_tables
/disk/tools/fs-NetBSD/makefs/fs.h
0,0 → 1,752
/* $NetBSD: fs.h,v 1.56 2011/03/06 17:08:38 bouyer Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fs.h 8.13 (Berkeley) 3/21/95
*/
 
/*
* NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
*/
 
#ifndef _UFS_FFS_FS_H_
#define _UFS_FFS_FS_H_
 
/*
* Each disk drive contains some number of file systems.
* A file system consists of a number of cylinder groups.
* Each cylinder group has inodes and data.
*
* A file system is described by its super-block, which in turn
* describes the cylinder groups. The super-block is critical
* data and is replicated in each cylinder group to protect against
* catastrophic loss. This is done at `newfs' time and the critical
* super-block data does not change, so the copies need not be
* referenced further unless disaster strikes.
*
* For file system fs, the offsets of the various blocks of interest
* are given in the super block as:
* [fs->fs_sblkno] Super-block
* [fs->fs_cblkno] Cylinder group block
* [fs->fs_iblkno] Inode blocks
* [fs->fs_dblkno] Data blocks
* The beginning of cylinder group cg in fs, is given by
* the ``cgbase(fs, cg)'' macro.
*
* Depending on the architecture and the media, the superblock may
* reside in any one of four places. For tiny media where every block
* counts, it is placed at the very front of the partition. Historically,
* UFS1 placed it 8K from the front to leave room for the disk label and
* a small bootstrap. For UFS2 it got moved to 64K from the front to leave
* room for the disk label and a bigger bootstrap, and for really piggy
* systems we check at 256K from the front if the first three fail. In
* all cases the size of the superblock will be SBLOCKSIZE. All values are
* given in byte-offset form, so they do not imply a sector size. The
* SBLOCKSEARCH specifies the order in which the locations should be searched.
*
* Unfortunately the UFS2/FFSv2 change was done without adequate consideration
* of backward compatibility. In particular 'newfs' for a FFSv2 partition
* must overwrite any old FFSv1 superblock at 8k, and preferrably as many
* of the alternates as it can find - otherwise attempting to mount on a
* system that only supports FFSv1 is likely to succeed!.
* For a small FFSv1 filesystem, an old FFSv2 superblock can be left on
* the disk, and a system that tries to find an FFSv2 filesystem in preference
* to and FFSv1 one (as NetBSD does) can mount the old FFSv2 filesystem.
* As a added bonus, the 'first alternate' superblock of a FFSv1 filesystem
* with 64k blocks is at 64k - just where the code looks first when playing
* 'hunt the superblock'.
*
* The ffsv2 superblock layout (which might contain an ffsv1 filesystem)
* can be detected by checking for sb->fs_old_flags & FS_FLAGS_UPDATED.
* This is the default superblock type for NetBSD since ffsv2 support was added.
*/
#define BBSIZE 8192
#define BBOFF ((off_t)(0))
#define BBLOCK ((daddr_t)(0))
 
#define SBLOCK_FLOPPY 0
#define SBLOCK_UFS1 8192
#define SBLOCK_UFS2 65536
#define SBLOCK_PIGGY 262144
#define SBLOCKSIZE 8192
/*
* NB: Do not, under any circumstances, look for an ffsv1 filesystem at
* SBLOCK_UFS2. Doing so will find the wrong superblock for filesystems
* with a 64k block size.
*/
#define SBLOCKSEARCH \
{ SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
 
/*
* Max number of fragments per block. This value is NOT tweakable.
*/
#define MAXFRAG 8
 
 
 
/*
* Addresses stored in inodes are capable of addressing fragments
* of `blocks'. File system blocks of at most size MAXBSIZE can
* be optionally broken into 2, 4, or 8 pieces, each of which is
* addressable; these pieces may be DEV_BSIZE, or some multiple of
* a DEV_BSIZE unit.
*
* Large files consist of exclusively large data blocks. To avoid
* undue wasted disk space, the last data block of a small file may be
* allocated as only as many fragments of a large block as are
* necessary. The file system format retains only a single pointer
* to such a fragment, which is a piece of a single large block that
* has been divided. The size of such a fragment is determinable from
* information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
*
* The file system records space availability at the fragment level;
* to determine block availability, aligned fragments are examined.
*/
 
/*
* MINBSIZE is the smallest allowable block size.
* In order to insure that it is possible to create files of size
* 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
* MINBSIZE must be big enough to hold a cylinder group block,
* thus changes to (struct cg) must keep its size within MINBSIZE.
* Note that super blocks are always of size SBSIZE,
* and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
*/
#define MINBSIZE 4096
 
/*
* The path name on which the file system is mounted is maintained
* in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
* the super block for this name.
*/
#define MAXMNTLEN 468
 
/*
* The volume name for this filesystem is maintained in fs_volname.
* MAXVOLLEN defines the length of the buffer allocated.
* This space used to be part of of fs_fsmnt.
*/
#define MAXVOLLEN 32
 
/*
* There is a 128-byte region in the superblock reserved for in-core
* pointers to summary information. Originally this included an array
* of pointers to blocks of struct csum; now there are just four
* pointers and the remaining space is padded with fs_ocsp[].
* NOCSPTRS determines the size of this padding. One pointer (fs_csp)
* is taken away to point to a contiguous array of struct csum for
* all cylinder groups; a second (fs_maxcluster) points to an array
* of cluster sizes that is computed as cylinder groups are inspected;
* the third (fs_contigdirs) points to an array that tracks the
* creation of new directories; and the fourth (fs_active) is used
* by snapshots.
*/
#define NOCSPTRS ((128 / sizeof(void *)) - 4)
 
/*
* A summary of contiguous blocks of various sizes is maintained
* in each cylinder group. Normally this is set by the initial
* value of fs_maxcontig. To conserve space, a maximum summary size
* is set by FS_MAXCONTIG.
*/
#define FS_MAXCONTIG 16
 
/*
* The maximum number of snapshot nodes that can be associated
* with each filesystem. This limit affects only the number of
* snapshot files that can be recorded within the superblock so
* that they can be found when the filesystem is mounted. However,
* maintaining too many will slow the filesystem performance, so
* having this limit is a good idea.
*/
#define FSMAXSNAP 20
 
/*
* Used to identify special blocks in snapshots:
*
* BLK_NOCOPY - A block that was unallocated at the time the snapshot
* was taken, hence does not need to be copied when written.
* BLK_SNAP - A block held by another snapshot that is not needed by this
* snapshot. When the other snapshot is freed, the BLK_SNAP entries
* are converted to BLK_NOCOPY. These are needed to allow fsck to
* identify blocks that are in use by other snapshots (which are
* expunged from this snapshot).
*/
#define BLK_NOCOPY ((daddr_t)(1))
#define BLK_SNAP ((daddr_t)(2))
 
/*
* MINFREE gives the minimum acceptable percentage of file system
* blocks which may be free. If the freelist drops below this level
* only the superuser may continue to allocate blocks. This may
* be set to 0 if no reserve of free blocks is deemed necessary,
* however throughput drops by fifty percent if the file system
* is run at between 95% and 100% full; thus the minimum default
* value of fs_minfree is 5%. However, to get good clustering
* performance, 10% is a better choice. This value is used only
* when creating a file system and can be overriden from the
* command line. By default we choose to optimize for time.
*/
#define MINFREE 5
#define DEFAULTOPT FS_OPTTIME
 
/*
* Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
* tune the layout preferences for directories within a filesystem.
* His algorithm can be tuned by adjusting the following parameters
* which tell the system the average file size and the average number
* of files per directory. These defaults are well selected for typical
* filesystems, but may need to be tuned for odd cases like filesystems
* being used for squid caches or news spools.
*/
#define AVFILESIZ 16384 /* expected average file size */
#define AFPDIR 64 /* expected number of files per directory */
 
/*
* Per cylinder group information; summarized in blocks allocated
* from first cylinder group data blocks. These blocks have to be
* read in from fs_csaddr (size fs_cssize) in addition to the
* super block.
*/
struct csum {
int32_t cs_ndir; /* number of directories */
int32_t cs_nbfree; /* number of free blocks */
int32_t cs_nifree; /* number of free inodes */
int32_t cs_nffree; /* number of free frags */
};
 
struct csum_total {
int64_t cs_ndir; /* number of directories */
int64_t cs_nbfree; /* number of free blocks */
int64_t cs_nifree; /* number of free inodes */
int64_t cs_nffree; /* number of free frags */
int64_t cs_spare[4]; /* future expansion */
};
 
 
/*
* Super block for an FFS file system in memory.
*/
struct fs {
int32_t fs_firstfield; /* historic file system linked list, */
int32_t fs_unused_1; /* used for incore super blocks */
int32_t fs_sblkno; /* addr of super-block in filesys */
int32_t fs_cblkno; /* offset of cyl-block in filesys */
int32_t fs_iblkno; /* offset of inode-blocks in filesys */
int32_t fs_dblkno; /* offset of first data after cg */
int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */
int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */
int32_t fs_old_time; /* last time written */
int32_t fs_old_size; /* number of blocks in fs */
int32_t fs_old_dsize; /* number of data blocks in fs */
int32_t fs_ncg; /* number of cylinder groups */
int32_t fs_bsize; /* size of basic blocks in fs */
int32_t fs_fsize; /* size of frag blocks in fs */
int32_t fs_frag; /* number of frags in a block in fs */
/* these are configuration parameters */
int32_t fs_minfree; /* minimum percentage of free blocks */
int32_t fs_old_rotdelay; /* num of ms for optimal next block */
int32_t fs_old_rps; /* disk revolutions per second */
/* these fields can be computed from the others */
int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
int32_t fs_fshift; /* ``numfrags'' calc number of frags */
/* these are configuration parameters */
int32_t fs_maxcontig; /* max number of contiguous blks */
int32_t fs_maxbpg; /* max number of blks per cyl group */
/* these fields can be computed from the others */
int32_t fs_fragshift; /* block to frag shift */
int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t fs_sbsize; /* actual size of super block */
int32_t fs_spare1[2]; /* old fs_csmask */
/* old fs_csshift */
int32_t fs_nindir; /* value of NINDIR */
int32_t fs_inopb; /* value of INOPB */
int32_t fs_old_nspf; /* value of NSPF */
/* yet another configuration parameter */
int32_t fs_optim; /* optimization preference, see below */
/* these fields are derived from the hardware */
int32_t fs_old_npsect; /* # sectors/track including spares */
int32_t fs_old_interleave; /* hardware sector interleave */
int32_t fs_old_trackskew; /* sector 0 skew, per track */
/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
int32_t fs_id[2]; /* unique file system id */
/* sizes determined by number of cylinder groups and their sizes */
int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */
int32_t fs_cssize; /* size of cyl grp summary area */
int32_t fs_cgsize; /* cylinder group size */
/* these fields are derived from the hardware */
int32_t fs_spare2; /* old fs_ntrak */
int32_t fs_old_nsect; /* sectors per track */
int32_t fs_old_spc; /* sectors per cylinder */
int32_t fs_old_ncyl; /* cylinders in file system */
int32_t fs_old_cpg; /* cylinders per group */
int32_t fs_ipg; /* inodes per group */
int32_t fs_fpg; /* blocks per group * fs_frag */
/* this data must be re-computed after crashes */
struct csum fs_old_cstotal; /* cylinder summary information */
/* these fields are cleared at mount time */
int8_t fs_fmod; /* super block modified flag */
uint8_t fs_clean; /* file system is clean flag */
int8_t fs_ronly; /* mounted read-only flag */
uint8_t fs_old_flags; /* see FS_ flags below */
u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
u_char fs_volname[MAXVOLLEN]; /* volume name */
uint64_t fs_swuid; /* system-wide uid */
int32_t fs_pad;
/* these fields retain the current block allocation info */
int32_t fs_cgrotor; /* last cg searched (UNUSED) */
void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
u_int8_t *fs_contigdirs; /* # of contiguously allocated dirs */
struct csum *fs_csp; /* cg summary info buffer for fs_cs */
int32_t *fs_maxcluster; /* max cluster in each cyl group */
u_char *fs_active; /* used by snapshots to track fs */
int32_t fs_old_cpc; /* cyl per cycle in postbl */
/* this area is otherwise allocated unless fs_old_flags & FS_FLAGS_UPDATED */
int32_t fs_maxbsize; /* maximum blocking factor permitted */
uint8_t fs_journal_version; /* journal format version */
uint8_t fs_journal_location; /* journal location type */
uint8_t fs_journal_reserved[2];/* reserved for future use */
uint32_t fs_journal_flags; /* journal flags */
uint64_t fs_journallocs[4]; /* location info for journal */
uint32_t fs_quota_magic; /* see quota2.h */
uint8_t fs_quota_flags; /* see quota2.h */
uint8_t fs_quota_reserved[3];
uint64_t fs_quotafile[2]; /* pointer to quota inodes */
int64_t fs_sparecon64[9]; /* reserved for future use */
int64_t fs_sblockloc; /* byte offset of standard superblock */
struct csum_total fs_cstotal; /* cylinder summary information */
int64_t fs_time; /* last time written */
int64_t fs_size; /* number of blocks in fs */
int64_t fs_dsize; /* number of data blocks in fs */
int64_t fs_csaddr; /* blk addr of cyl grp summary area */
int64_t fs_pendingblocks; /* blocks in process of being freed */
int32_t fs_pendinginodes; /* inodes in process of being freed */
int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
/* back to stuff that has been around a while */
int32_t fs_avgfilesize; /* expected average file size */
int32_t fs_avgfpdir; /* expected # of files per directory */
int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
int32_t fs_sparecon32[26]; /* reserved for future constants */
uint32_t fs_flags; /* see FS_ flags below */
/* back to stuff that has been around a while (again) */
int32_t fs_contigsumsize; /* size of cluster summary array */
int32_t fs_maxsymlinklen; /* max length of an internal symlink */
int32_t fs_old_inodefmt; /* format of on-disk inodes */
u_int64_t fs_maxfilesize; /* maximum representable file size */
int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
int32_t fs_state; /* validate fs_clean field (UNUSED) */
int32_t fs_old_postblformat; /* format of positional layout tables */
int32_t fs_old_nrpos; /* number of rotational positions */
int32_t fs_spare5[2]; /* old fs_postbloff */
/* old fs_rotbloff */
int32_t fs_magic; /* magic number */
};
 
#define fs_old_postbloff fs_spare5[0]
#define fs_old_rotbloff fs_spare5[1]
#define fs_old_postbl_start fs_maxbsize
#define fs_old_headswitch fs_id[0]
#define fs_old_trkseek fs_id[1]
#define fs_old_csmask fs_spare1[0]
#define fs_old_csshift fs_spare1[1]
 
#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
 
#define old_fs_postbl(fs_, cylno, opostblsave) \
((((fs_)->fs_old_postblformat == FS_42POSTBLFMT) || \
((fs_)->fs_old_postbloff == offsetof(struct fs, fs_old_postbl_start))) \
? ((int16_t *)(opostblsave) + (cylno) * (fs_)->fs_old_nrpos) \
: ((int16_t *)((uint8_t *)(fs_) + \
(fs_)->fs_old_postbloff) + (cylno) * (fs_)->fs_old_nrpos))
#define old_fs_rotbl(fs) \
(((fs)->fs_old_postblformat == FS_42POSTBLFMT) \
? ((uint8_t *)(&(fs)->fs_magic+1)) \
: ((uint8_t *)((uint8_t *)(fs) + (fs)->fs_old_rotbloff)))
 
/*
* File system identification
*/
#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast file system magic number */
#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast file system magic number */
#define FS_UFS1_MAGIC_SWAPPED 0x54190100
#define FS_UFS2_MAGIC_SWAPPED 0x19015419
#define FS_OKAY 0x7c269d38 /* superblock checksum */
#define FS_42INODEFMT -1 /* 4.2BSD inode format */
#define FS_44INODEFMT 2 /* 4.4BSD inode format */
 
/*
* File system clean flags
*/
#define FS_ISCLEAN 0x01
#define FS_WASCLEAN 0x02
 
/*
* Preference for optimization.
*/
#define FS_OPTTIME 0 /* minimize allocation time */
#define FS_OPTSPACE 1 /* minimize disk fragmentation */
 
/*
* File system flags
*/
#define FS_UNCLEAN 0x001 /* file system not clean at mount (unused) */
#define FS_DOSOFTDEP 0x002 /* file system using soft dependencies */
#define FS_NEEDSFSCK 0x004 /* needs sync fsck (FreeBSD compat, unused) */
#define FS_INDEXDIRS 0x008 /* kernel supports indexed directories */
#define FS_ACLS 0x010 /* file system has ACLs enabled */
#define FS_MULTILABEL 0x020 /* file system is MAC multi-label */
#define FS_GJOURNAL 0x40 /* gjournaled file system */
#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
#define FS_DOWAPBL 0x100 /* Write ahead physical block logging */
#define FS_DOQUOTA2 0x200 /* in-filesystem quotas */
 
/* File system flags that are ok for NetBSD if set in fs_flags */
#define FS_KNOWN_FLAGS (FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2)
 
/*
* File system internal flags, also in fs_flags.
* (Pick highest number to avoid conflicts with others)
*/
#define FS_SWAPPED 0x80000000 /* file system is endian swapped */
#define FS_INTERNAL 0x80000000 /* mask for internal flags */
 
/*
* Macros to access bits in the fs_active array.
*/
#define ACTIVECG_SET(fs, cg) \
do { \
if ((fs)->fs_active != NULL) \
setbit((fs)->fs_active, (cg)); \
} while (/*CONSTCOND*/ 0)
#define ACTIVECG_CLR(fs, cg) \
do { \
if ((fs)->fs_active != NULL) \
clrbit((fs)->fs_active, (cg)); \
} while (/*CONSTCOND*/ 0)
#define ACTIVECG_ISSET(fs, cg) \
((fs)->fs_active != NULL && isset((fs)->fs_active, (cg)))
 
/*
* The size of a cylinder group is calculated by CGSIZE. The maximum size
* is limited by the fact that cylinder groups are at most one block.
* Its size is derived from the size of the maps maintained in the
* cylinder group and the (struct cg) size.
*/
#define CGSIZE_IF(fs, ipg, fpg) \
/* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \
/* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \
/* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \
/* inode map */ howmany((ipg), NBBY) + \
/* block map */ howmany((fpg), NBBY) +\
/* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
/* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \
/* cluster map */ howmany(fragstoblks(fs, (fpg)), NBBY)))
 
#define CGSIZE(fs) CGSIZE_IF((fs), (fs)->fs_ipg, (fs)->fs_fpg)
 
/*
* The minimal number of cylinder groups that should be created.
*/
#define MINCYLGRPS 4
 
 
/*
* Convert cylinder group to base address of its global summary info.
*/
#define fs_cs(fs, indx) fs_csp[indx]
 
/*
* Cylinder group block for a file system.
*/
#define CG_MAGIC 0x090255
struct cg {
int32_t cg_firstfield; /* historic cyl groups linked list */
int32_t cg_magic; /* magic number */
int32_t cg_old_time; /* time last written */
int32_t cg_cgx; /* we are the cgx'th cylinder group */
int16_t cg_old_ncyl; /* number of cyl's this cg */
int16_t cg_old_niblk; /* number of inode blocks this cg */
int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int32_t cg_rotor; /* position of last used block */
int32_t cg_frotor; /* position of last used frag */
int32_t cg_irotor; /* position of last used inode */
int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
int32_t cg_old_btotoff; /* (int32) block totals per cylinder */
int32_t cg_old_boff; /* (u_int16) free block positions */
int32_t cg_iusedoff; /* (u_int8) used inode map */
int32_t cg_freeoff; /* (u_int8) free block map */
int32_t cg_nextfreeoff; /* (u_int8) next available space */
int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */
int32_t cg_clusteroff; /* (u_int8) free cluster map */
int32_t cg_nclusterblks; /* number of clusters this cg */
int32_t cg_niblk; /* number of inode blocks this cg */
int32_t cg_initediblk; /* last initialized inode */
int32_t cg_sparecon32[3]; /* reserved for future use */
int64_t cg_time; /* time last written */
int64_t cg_sparecon64[3]; /* reserved for future use */
u_int8_t cg_space[1]; /* space for cylinder group maps */
/* actually longer */
};
 
/*
* The following structure is defined
* for compatibility with old file systems.
*/
struct ocg {
int32_t cg_firstfield; /* historic linked list of cyl groups */
int32_t cg_unused_1; /* used for incore cyl groups */
int32_t cg_time; /* time last written */
int32_t cg_cgx; /* we are the cgx'th cylinder group */
int16_t cg_ncyl; /* number of cyl's this cg */
int16_t cg_niblk; /* number of inode blocks this cg */
int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int32_t cg_rotor; /* position of last used block */
int32_t cg_frotor; /* position of last used frag */
int32_t cg_irotor; /* position of last used inode */
int32_t cg_frsum[8]; /* counts of available frags */
int32_t cg_btot[32]; /* block totals per cylinder */
int16_t cg_b[32][8]; /* positions of free blocks */
u_int8_t cg_iused[256]; /* used inode map */
int32_t cg_magic; /* magic number */
u_int8_t cg_free[1]; /* free block map */
/* actually longer */
};
 
 
/*
* Macros for access to cylinder group array structures.
*/
#define old_cg_blktot_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_btot)
#define old_cg_blks_old(fs, cgp, cylno, ns) \
(((struct ocg *)(cgp))->cg_b[cylno])
 
#define old_cg_blktot_new(cgp, ns) \
((int32_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_old_btotoff, (ns))))
#define old_cg_blks_new(fs, cgp, cylno, ns) \
((int16_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_old_boff, (ns))) + (cylno) * (fs)->fs_old_nrpos)
 
#define old_cg_blktot(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
old_cg_blktot_old(cgp, ns) : old_cg_blktot_new(cgp, ns))
#define old_cg_blks(fs, cgp, cylno, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
old_cg_blks_old(fs, cgp, cylno, ns) : old_cg_blks_new(fs, cgp, cylno, ns))
 
#define cg_inosused_new(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_iusedoff, (ns))))
#define cg_blksfree_new(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_freeoff, (ns))))
#define cg_chkmagic_new(cgp, ns) \
(ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
 
#define cg_inosused_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_iused)
#define cg_blksfree_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_free)
#define cg_chkmagic_old(cgp, ns) \
(ufs_rw32(((struct ocg *)(cgp))->cg_magic, (ns)) == CG_MAGIC)
 
#define cg_inosused(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
cg_inosused_old(cgp, ns) : cg_inosused_new(cgp, ns))
#define cg_blksfree(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
cg_blksfree_old(cgp, ns) : cg_blksfree_new(cgp, ns))
#define cg_chkmagic(cgp, ns) \
(cg_chkmagic_new(cgp, ns) || cg_chkmagic_old(cgp, ns))
 
#define cg_clustersfree(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_clusteroff, (ns))))
#define cg_clustersum(cgp, ns) \
((int32_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_clustersumoff, (ns))))
 
 
/*
* Turn file system block numbers into disk block addresses.
* This maps file system blocks to device size blocks.
*/
#if defined (_KERNEL)
#define fsbtodb(fs, b) ((b) << ((fs)->fs_fshift - DEV_BSHIFT))
#define dbtofsb(fs, b) ((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
#else
#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
#endif
 
/*
* Cylinder group macros to locate things in cylinder groups.
* They calc file system addresses of cylinder group data structures.
*/
#define cgbase(fs, c) (((daddr_t)(fs)->fs_fpg) * (c))
#define cgstart_ufs1(fs, c) \
(cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))
#define cgstart_ufs2(fs, c) cgbase((fs), (c))
#define cgstart(fs, c) ((fs)->fs_magic == FS_UFS2_MAGIC \
? cgstart_ufs2((fs), (c)) : cgstart_ufs1((fs), (c)))
#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
 
/*
* Macros for handling inode numbers:
* inode number to file system block offset.
* inode number to cylinder group number.
* inode number to file system block address.
*/
#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
#define ino_to_fsba(fs, x) \
((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
 
/*
* Give cylinder group number for a file system block.
* Give cylinder group block number for a file system block.
*/
#define dtog(fs, d) ((d) / (fs)->fs_fpg)
#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
 
/*
* Extract the bits for a block from a map.
* Compute the cylinder and rotational position of a cyl block addr.
*/
#define blkmap(fs, map, loc) \
(((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
#define old_cbtocylno(fs, bno) \
(fsbtodb(fs, bno) / (fs)->fs_old_spc)
#define old_cbtorpos(fs, bno) \
((fs)->fs_old_nrpos <= 1 ? 0 : \
(fsbtodb(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
fsbtodb(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
(fs)->fs_old_nsect * (fs)->fs_old_nrpos / (fs)->fs_old_npsect)
 
/*
* The following macros optimize certain frequently calculated
* quantities by using shifts and masks in place of divisions
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
((loc) & (fs)->fs_qbmask)
#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
((loc) & (fs)->fs_qfmask)
#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
(((off_t)(frag)) << (fs)->fs_fshift)
#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
(((off_t)(blk)) << (fs)->fs_bshift)
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
((loc) >> (fs)->fs_bshift)
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
((loc) >> (fs)->fs_fshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
(((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
(((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
((frags) >> (fs)->fs_fragshift)
#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
((blks) << (fs)->fs_fragshift)
#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
((fsb) & ((fs)->fs_frag - 1))
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
((fsb) &~ ((fs)->fs_frag - 1))
 
/*
* Determine the number of available frags given a
* percentage to hold in reserve.
*/
#define freespace(fs, percentreserved) \
(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
(fs)->fs_cstotal.cs_nffree - \
(((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
 
/*
* Determining the size of a file block in the file system.
*/
#define blksize(fs, ip, lbn) \
(((lbn) >= NDADDR || (ip)->i_size >= lblktosize(fs, (lbn) + 1)) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_size))))
 
#define sblksize(fs, size, lbn) \
(((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (size)))))
 
 
/*
* Number of inodes in a secondary storage block/fragment.
*/
#define INOPB(fs) ((fs)->fs_inopb)
#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
 
/*
* Number of indirects in a file system block.
*/
#define NINDIR(fs) ((fs)->fs_nindir)
 
/*
* Apple UFS Label:
* We check for this to decide to use APPLEUFS_DIRBLKSIZ
*/
#define APPLEUFS_LABEL_MAGIC 0x4c41424c /* LABL */
#define APPLEUFS_LABEL_SIZE 1024
#define APPLEUFS_LABEL_OFFSET (BBSIZE - APPLEUFS_LABEL_SIZE) /* located at 7k */
#define APPLEUFS_LABEL_VERSION 1
#define APPLEUFS_MAX_LABEL_NAME 512
 
struct appleufslabel {
u_int32_t ul_magic;
u_int16_t ul_checksum;
u_int16_t ul_unused0;
u_int32_t ul_version;
u_int32_t ul_time;
u_int16_t ul_namelen;
u_char ul_name[APPLEUFS_MAX_LABEL_NAME]; /* Warning: may not be null terminated */
u_int16_t ul_unused1;
u_int64_t ul_uuid; /* Note this is only 4 byte aligned */
u_char ul_reserved[24];
u_char ul_unused[460];
} __packed;
 
 
#endif /* !_UFS_FFS_FS_H_ */
/disk/tools/fs-NetBSD/makefs/ffs.c
0,0 → 1,1156
/* $NetBSD: ffs.c,v 1.46 2012/01/28 02:35:46 christos Exp $ */
 
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: ffs.c,v 1.46 2012/01/28 02:35:46 christos Exp $");
#endif /* !__lint */
 
#include <sys/param.h>
 
#if !HAVE_NBTOOL_CONFIG_H
#include <sys/mount.h>
#endif
 
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
 
#include "common.h"
#include "makefs.h"
#include "ffs.h"
 
#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
#include <sys/statvfs.h>
#endif
 
#include "dinode.h"
#include "dir.h"
#include "fs.h"
#include "ufs_bswap.h"
 
#include "ufs_inode.h"
#include "newfs_extern.h"
#include "ffs_extern.h"
 
#undef DIP
#define DIP(dp, field) \
((ffs_opts->version == 1) ? \
(dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field)
 
/*
* Various file system defaults (cribbed from newfs(8)).
*/
#define DFL_FRAGSIZE 1024 /* fragment size */
#define DFL_BLKSIZE 8192 /* block size */
#define DFL_SECSIZE 512 /* sector size */
#define DFL_CYLSPERGROUP 65536 /* cylinders per group */
#define DFL_FRAGSPERINODE 4 /* fragments per inode */
#define DFL_ROTDELAY 0 /* rotational delay */
#define DFL_NRPOS 1 /* rotational positions */
#define DFL_RPM 3600 /* rpm of disk */
#define DFL_NSECTORS 64 /* # of sectors */
#define DFL_NTRACKS 16 /* # of tracks */
 
 
typedef struct {
u_char *buf; /* buf for directory */
doff_t size; /* full size of buf */
doff_t cur; /* offset of current entry */
} dirbuf_t;
 
 
static int ffs_create_image(const char *, fsinfo_t *);
static void ffs_dump_fsinfo(fsinfo_t *);
static void ffs_dump_dirbuf(dirbuf_t *, const char *, int);
static void ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int);
static int ffs_populate_dir(const char *, fsnode *, fsinfo_t *);
static void ffs_size_dir(fsnode *, fsinfo_t *);
static void ffs_validate(const char *, fsnode *, fsinfo_t *);
static void ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *);
static void ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *);
static void *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *,
fsnode *, fsinfo_t *);
static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *,
fsnode *, fsinfo_t *);
 
 
 
int sectorsize; /* XXX: for buf.c::getblk() */
 
/* publically visible functions */
 
void
ffs_prep_opts(fsinfo_t *fsopts)
{
ffs_opt_t *ffs_opts;
 
if ((ffs_opts = calloc(1, sizeof(ffs_opt_t))) == NULL)
err(1, "Allocating memory for ffs_options");
 
fsopts->fs_specific = ffs_opts;
 
ffs_opts->bsize= -1;
ffs_opts->fsize= -1;
ffs_opts->cpg= -1;
ffs_opts->density= -1;
ffs_opts->minfree= -1;
ffs_opts->optimization= -1;
ffs_opts->maxcontig= -1;
ffs_opts->maxbpg= -1;
ffs_opts->avgfilesize= -1;
ffs_opts->avgfpdir= -1;
ffs_opts->version = 1;
}
 
void
ffs_cleanup_opts(fsinfo_t *fsopts)
{
if (fsopts->fs_specific)
free(fsopts->fs_specific);
}
 
int
ffs_parse_opts(const char *option, fsinfo_t *fsopts)
{
ffs_opt_t *ffs_opts = fsopts->fs_specific;
 
option_t ffs_options[] = {
{ "bsize", &ffs_opts->bsize, 1, INT_MAX,
"block size" },
{ "fsize", &ffs_opts->fsize, 1, INT_MAX,
"fragment size" },
{ "density", &ffs_opts->density, 1, INT_MAX,
"bytes per inode" },
{ "minfree", &ffs_opts->minfree, 0, 99,
"minfree" },
{ "maxbpf", &ffs_opts->maxbpg, 1, INT_MAX,
"max blocks per file in a cg" },
{ "avgfilesize", &ffs_opts->avgfilesize,1, INT_MAX,
"expected average file size" },
{ "avgfpdir", &ffs_opts->avgfpdir, 1, INT_MAX,
"expected # of files per directory" },
{ "extent", &ffs_opts->maxbsize, 1, INT_MAX,
"maximum # extent size" },
{ "maxbpcg", &ffs_opts->maxblkspercg,1, INT_MAX,
"max # of blocks per group" },
{ "version", &ffs_opts->version, 1, 2,
"UFS version" },
{ .name = NULL }
};
 
char *var, *val;
int rv;
 
assert(option != NULL);
assert(fsopts != NULL);
assert(ffs_opts != NULL);
 
if (debug & DEBUG_FS_PARSE_OPTS)
printf("ffs_parse_opts: got `%s'\n", option);
 
if ((var = strdup(option)) == NULL)
err(1, "Allocating memory for copy of option string");
rv = 0;
 
if ((val = strchr(var, '=')) == NULL) {
warnx("Option `%s' doesn't contain a value", var);
goto leave_ffs_parse_opts;
}
*val++ = '\0';
 
if (strcmp(var, "optimization") == 0) {
if (strcmp(val, "time") == 0) {
ffs_opts->optimization = FS_OPTTIME;
} else if (strcmp(val, "space") == 0) {
ffs_opts->optimization = FS_OPTSPACE;
} else {
warnx("Invalid optimization `%s'", val);
goto leave_ffs_parse_opts;
}
rv = 1;
} else if (strcmp(var, "label") == 0) {
/* !!!!! HG: */
//strlcpy(ffs_opts->label, val, sizeof(ffs_opts->label));
strncpy(ffs_opts->label, val, sizeof(ffs_opts->label));
/* :HG !!!!! */
rv = 1;
} else
rv = set_option(ffs_options, var, val);
 
leave_ffs_parse_opts:
if (var)
free(var);
return (rv);
}
 
 
void
ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
{
struct fs *superblock;
struct timeval start;
 
assert(image != NULL);
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
 
if (debug & DEBUG_FS_MAKEFS)
printf("ffs_makefs: image %s directory %s root %p\n",
image, dir, root);
 
/* validate tree and options */
TIMER_START(start);
ffs_validate(dir, root, fsopts);
TIMER_RESULTS(start, "ffs_validate");
 
printf("Calculated size of `%s': %lld bytes, %lld inodes\n",
image, (long long)fsopts->size, (long long)fsopts->inodes);
 
/* create image */
TIMER_START(start);
if (ffs_create_image(image, fsopts) == -1)
errx(1, "Image file `%s' not created.", image);
TIMER_RESULTS(start, "ffs_create_image");
 
fsopts->curinode = ROOTINO;
 
if (debug & DEBUG_FS_MAKEFS)
putchar('\n');
 
/* populate image */
printf("Populating `%s'\n", image);
TIMER_START(start);
if (! ffs_populate_dir(dir, root, fsopts))
errx(1, "Image file `%s' not populated.", image);
TIMER_RESULTS(start, "ffs_populate_dir");
 
/* ensure no outstanding buffers remain */
if (debug & DEBUG_FS_MAKEFS)
bcleanup();
 
/* update various superblock parameters */
superblock = fsopts->superblock;
superblock->fs_fmod = 0;
superblock->fs_old_cstotal.cs_ndir = superblock->fs_cstotal.cs_ndir;
superblock->fs_old_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree;
superblock->fs_old_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree;
superblock->fs_old_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree;
 
/* write out superblock; image is now complete */
ffs_write_superblock(fsopts->superblock, fsopts);
if (close(fsopts->fd) == -1)
err(1, "Closing `%s'", image);
fsopts->fd = -1;
printf("Image `%s' complete\n", image);
}
 
/* end of public functions */
 
 
static void
ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
{
int32_t ncg = 1;
#if notyet
int32_t spc, nspf, ncyl, fssize;
#endif
ffs_opt_t *ffs_opts = fsopts->fs_specific;
 
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
assert(ffs_opts != NULL);
 
if (debug & DEBUG_FS_VALIDATE) {
printf("ffs_validate: before defaults set:\n");
ffs_dump_fsinfo(fsopts);
}
 
/* set FFS defaults */
if (fsopts->sectorsize == -1)
fsopts->sectorsize = DFL_SECSIZE;
if (ffs_opts->fsize == -1)
ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
if (ffs_opts->bsize == -1)
ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize);
if (ffs_opts->cpg == -1)
ffs_opts->cpg = DFL_CYLSPERGROUP;
else
ffs_opts->cpgflg = 1;
/* fsopts->density is set below */
if (ffs_opts->nsectors == -1)
ffs_opts->nsectors = DFL_NSECTORS;
if (ffs_opts->minfree == -1)
ffs_opts->minfree = MINFREE;
if (ffs_opts->optimization == -1)
ffs_opts->optimization = DEFAULTOPT;
if (ffs_opts->maxcontig == -1)
ffs_opts->maxcontig =
MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize);
/* XXX ondisk32 */
if (ffs_opts->maxbpg == -1)
ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t);
if (ffs_opts->avgfilesize == -1)
ffs_opts->avgfilesize = AVFILESIZ;
if (ffs_opts->avgfpdir == -1)
ffs_opts->avgfpdir = AFPDIR;
 
/* calculate size of tree */
ffs_size_dir(root, fsopts);
fsopts->inodes += ROOTINO; /* include first two inodes */
 
if (debug & DEBUG_FS_VALIDATE)
printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n",
(long long)fsopts->size, (long long)fsopts->inodes);
 
/* add requested slop */
fsopts->size += fsopts->freeblocks;
fsopts->inodes += fsopts->freefiles;
if (fsopts->freefilepc > 0)
fsopts->inodes =
fsopts->inodes * (100 + fsopts->freefilepc) / 100;
if (fsopts->freeblockpc > 0)
fsopts->size =
fsopts->size * (100 + fsopts->freeblockpc) / 100;
 
/* add space needed for superblocks */
/*
* The old SBOFF (SBLOCK_UFS1) is used here because makefs is
* typically used for small filesystems where space matters.
* XXX make this an option.
*/
fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
/* add space needed to store inodes, x3 for blockmaps, etc */
if (ffs_opts->version == 1)
fsopts->size += ncg * DINODE1_SIZE *
roundup(fsopts->inodes / ncg,
ffs_opts->bsize / DINODE1_SIZE);
else
fsopts->size += ncg * DINODE2_SIZE *
roundup(fsopts->inodes / ncg,
ffs_opts->bsize / DINODE2_SIZE);
 
/* add minfree */
if (ffs_opts->minfree > 0)
fsopts->size =
fsopts->size * (100 + ffs_opts->minfree) / 100;
/*
* XXX any other fs slop to add, such as csum's, bitmaps, etc ??
*/
 
if (fsopts->size < fsopts->minsize) /* ensure meets minimum size */
fsopts->size = fsopts->minsize;
 
/* round up to the next block */
fsopts->size = roundup(fsopts->size, ffs_opts->bsize);
 
/* calculate density if necessary */
if (ffs_opts->density == -1)
ffs_opts->density = fsopts->size / fsopts->inodes + 1;
 
if (debug & DEBUG_FS_VALIDATE) {
printf("ffs_validate: after defaults set:\n");
ffs_dump_fsinfo(fsopts);
printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n",
dir, (long long)fsopts->size, (long long)fsopts->inodes);
}
sectorsize = fsopts->sectorsize; /* XXX - see earlier */
 
/* now check calculated sizes vs requested sizes */
if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
dir, (long long)fsopts->size, (long long)fsopts->maxsize);
}
}
 
 
static void
ffs_dump_fsinfo(fsinfo_t *f)
{
 
ffs_opt_t *fs = f->fs_specific;
 
printf("fsopts at %p\n", f);
 
printf("\tsize %lld, inodes %lld, curinode %u\n",
(long long)f->size, (long long)f->inodes, f->curinode);
 
printf("\tminsize %lld, maxsize %lld\n",
(long long)f->minsize, (long long)f->maxsize);
printf("\tfree files %lld, freefile %% %d\n",
(long long)f->freefiles, f->freefilepc);
printf("\tfree blocks %lld, freeblock %% %d\n",
(long long)f->freeblocks, f->freeblockpc);
printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize);
 
printf("\tbsize %d, fsize %d, cpg %d, density %d\n",
fs->bsize, fs->fsize, fs->cpg, fs->density);
printf("\tnsectors %d, rpm %d, minfree %d\n",
fs->nsectors, fs->rpm, fs->minfree);
printf("\tmaxcontig %d, maxbpg %d\n",
fs->maxcontig, fs->maxbpg);
printf("\toptimization %s\n",
fs->optimization == FS_OPTSPACE ? "space" : "time");
}
 
 
static int
ffs_create_image(const char *image, fsinfo_t *fsopts)
{
#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
struct statvfs sfs;
#endif
struct fs *fs;
char *buf;
int i, bufsize;
off_t bufrem;
 
assert (image != NULL);
assert (fsopts != NULL);
 
/* create image */
if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666))
== -1) {
warn("Can't open `%s' for writing", image);
return (-1);
}
 
/* zero image */
#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
if (fstatvfs(fsopts->fd, &sfs) == -1) {
#endif
bufsize = 8192;
#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
warn("can't fstatvfs `%s', using default %d byte chunk",
image, bufsize);
} else
bufsize = sfs.f_iosize;
#endif
bufrem = fsopts->size;
if (debug & DEBUG_FS_CREATE_IMAGE)
printf(
"zero-ing image `%s', %lld sectors, using %d byte chunks\n",
image, (long long)bufrem, bufsize);
if ((buf = calloc(1, bufsize)) == NULL) {
warn("Can't create buffer for sector");
return (-1);
}
while (bufrem > 0) {
i = write(fsopts->fd, buf, MIN(bufsize, bufrem));
if (i == -1) {
warn("zeroing image, %lld bytes to go",
(long long)bufrem);
free(buf);
return (-1);
}
bufrem -= i;
}
free(buf);
 
/* make the file system */
if (debug & DEBUG_FS_CREATE_IMAGE)
printf("calling mkfs(\"%s\", ...)\n", image);
fs = ffs_mkfs(image, fsopts);
fsopts->superblock = (void *)fs;
if (debug & DEBUG_FS_CREATE_IMAGE) {
time_t t;
 
t = (time_t)((struct fs *)fsopts->superblock)->fs_time;
printf("mkfs returned %p; fs_time %s",
fsopts->superblock, ctime(&t));
printf("fs totals: nbfree %lld, nffree %lld, nifree %lld, ndir %lld\n",
(long long)fs->fs_cstotal.cs_nbfree,
(long long)fs->fs_cstotal.cs_nffree,
(long long)fs->fs_cstotal.cs_nifree,
(long long)fs->fs_cstotal.cs_ndir);
}
 
if (fs->fs_cstotal.cs_nifree + ROOTINO < fsopts->inodes) {
warnx(
"Image file `%s' has %lld free inodes; %lld are required.",
image,
(long long)(fs->fs_cstotal.cs_nifree + ROOTINO),
(long long)fsopts->inodes);
return (-1);
}
return (fsopts->fd);
}
 
 
static void
ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
{
struct direct tmpdir;
fsnode * node;
int curdirsize, this;
ffs_opt_t *ffs_opts = fsopts->fs_specific;
 
/* node may be NULL (empty directory) */
assert(fsopts != NULL);
assert(ffs_opts != NULL);
 
if (debug & DEBUG_FS_SIZE_DIR)
printf("ffs_size_dir: entry: bytes %lld inodes %lld\n",
(long long)fsopts->size, (long long)fsopts->inodes);
 
#define ADDDIRENT(e) do { \
tmpdir.d_namlen = strlen((e)); \
this = DIRSIZ(0, &tmpdir, 0); \
if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \
printf("ADDDIRENT: was: %s (%d) this %d cur %d\n", \
e, tmpdir.d_namlen, this, curdirsize); \
if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ)) \
curdirsize = roundup(curdirsize, DIRBLKSIZ); \
curdirsize += this; \
if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \
printf("ADDDIRENT: now: %s (%d) this %d cur %d\n", \
e, tmpdir.d_namlen, this, curdirsize); \
} while (0);
 
/*
* XXX this needs to take into account extra space consumed
* by indirect blocks, etc.
*/
#define ADDSIZE(x) do { \
fsopts->size += roundup((x), ffs_opts->fsize); \
} while (0);
 
curdirsize = 0;
for (node = root; node != NULL; node = node->next) {
ADDDIRENT(node->name);
if (node == root) { /* we're at "." */
assert(strcmp(node->name, ".") == 0);
ADDDIRENT("..");
} else if ((node->inode->flags & FI_SIZED) == 0) {
/* don't count duplicate names */
node->inode->flags |= FI_SIZED;
if (debug & DEBUG_FS_SIZE_DIR_NODE)
printf("ffs_size_dir: `%s' size %lld\n",
node->name,
(long long)node->inode->st.st_size);
fsopts->inodes++;
if (node->type == S_IFREG)
ADDSIZE(node->inode->st.st_size);
if (node->type == S_IFLNK) {
int slen;
 
slen = strlen(node->symlink) + 1;
if (slen >= (ffs_opts->version == 1 ?
MAXSYMLINKLEN_UFS1 :
MAXSYMLINKLEN_UFS2))
ADDSIZE(slen);
}
}
if (node->type == S_IFDIR)
ffs_size_dir(node->child, fsopts);
}
ADDSIZE(curdirsize);
 
if (debug & DEBUG_FS_SIZE_DIR)
printf("ffs_size_dir: exit: size %lld inodes %lld\n",
(long long)fsopts->size, (long long)fsopts->inodes);
}
 
static void *
ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
fsnode *root, fsinfo_t *fsopts)
{
int slen;
void *membuf;
 
memset(dinp, 0, sizeof(*dinp));
dinp->di_mode = cur->inode->st.st_mode;
dinp->di_nlink = cur->inode->nlink;
dinp->di_size = cur->inode->st.st_size;
dinp->di_atime = cur->inode->st.st_atime;
dinp->di_mtime = cur->inode->st.st_mtime;
dinp->di_ctime = cur->inode->st.st_ctime;
#if HAVE_STRUCT_STAT_ST_MTIMENSEC
dinp->di_atimensec = cur->inode->st.st_atimensec;
dinp->di_mtimensec = cur->inode->st.st_mtimensec;
dinp->di_ctimensec = cur->inode->st.st_ctimensec;
#endif
#if HAVE_STRUCT_STAT_ST_FLAGS
dinp->di_flags = cur->inode->st.st_flags;
#endif
#if HAVE_STRUCT_STAT_ST_GEN
dinp->di_gen = cur->inode->st.st_gen;
#endif
dinp->di_uid = cur->inode->st.st_uid;
dinp->di_gid = cur->inode->st.st_gid;
/* not set: di_db, di_ib, di_blocks, di_spare */
 
membuf = NULL;
if (cur == root) { /* "."; write dirbuf */
membuf = dbufp->buf;
dinp->di_size = dbufp->size;
} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
dinp->di_size = 0; /* a device */
dinp->di_rdev =
ufs_rw32(cur->inode->st.st_rdev, fsopts->needswap);
} else if (S_ISLNK(cur->type)) { /* symlink */
slen = strlen(cur->symlink);
if (slen < MAXSYMLINKLEN_UFS1) { /* short link */
memcpy(dinp->di_db, cur->symlink, slen);
} else
membuf = cur->symlink;
dinp->di_size = slen;
}
return membuf;
}
 
static void *
ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
fsnode *root, fsinfo_t *fsopts)
{
int slen;
void *membuf;
 
memset(dinp, 0, sizeof(*dinp));
dinp->di_mode = cur->inode->st.st_mode;
dinp->di_nlink = cur->inode->nlink;
dinp->di_size = cur->inode->st.st_size;
dinp->di_atime = cur->inode->st.st_atime;
dinp->di_mtime = cur->inode->st.st_mtime;
dinp->di_ctime = cur->inode->st.st_ctime;
#if HAVE_STRUCT_STAT_ST_MTIMENSEC
dinp->di_atimensec = cur->inode->st.st_atimensec;
dinp->di_mtimensec = cur->inode->st.st_mtimensec;
dinp->di_ctimensec = cur->inode->st.st_ctimensec;
#endif
#if HAVE_STRUCT_STAT_ST_FLAGS
dinp->di_flags = cur->inode->st.st_flags;
#endif
#if HAVE_STRUCT_STAT_ST_GEN
dinp->di_gen = cur->inode->st.st_gen;
#endif
#if HAVE_STRUCT_STAT_BIRTHTIME
dinp->di_birthtime = cur->inode->st.st_birthtime;
dinp->di_birthnsec = cur->inode->st.st_birthtimensec;
#endif
dinp->di_uid = cur->inode->st.st_uid;
dinp->di_gid = cur->inode->st.st_gid;
/* not set: di_db, di_ib, di_blocks, di_spare */
 
membuf = NULL;
if (cur == root) { /* "."; write dirbuf */
membuf = dbufp->buf;
dinp->di_size = dbufp->size;
} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
dinp->di_size = 0; /* a device */
dinp->di_rdev =
ufs_rw64(cur->inode->st.st_rdev, fsopts->needswap);
} else if (S_ISLNK(cur->type)) { /* symlink */
slen = strlen(cur->symlink);
if (slen < MAXSYMLINKLEN_UFS2) { /* short link */
memcpy(dinp->di_db, cur->symlink, slen);
} else
membuf = cur->symlink;
dinp->di_size = slen;
}
return membuf;
}
 
static int
ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
{
fsnode *cur;
dirbuf_t dirbuf;
union dinode din;
void *membuf;
char path[MAXPATHLEN + 1];
ffs_opt_t *ffs_opts = fsopts->fs_specific;
 
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
assert(ffs_opts != NULL);
 
(void)memset(&dirbuf, 0, sizeof(dirbuf));
 
if (debug & DEBUG_FS_POPULATE)
printf("ffs_populate_dir: PASS 1 dir %s node %p\n", dir, root);
 
/*
* pass 1: allocate inode numbers, build directory `file'
*/
for (cur = root; cur != NULL; cur = cur->next) {
if ((cur->inode->flags & FI_ALLOCATED) == 0) {
cur->inode->flags |= FI_ALLOCATED;
if (cur == root && cur->parent != NULL)
cur->inode->ino = cur->parent->inode->ino;
else {
cur->inode->ino = fsopts->curinode;
fsopts->curinode++;
}
}
ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap);
if (cur == root) { /* we're at "."; add ".." */
ffs_make_dirbuf(&dirbuf, "..",
cur->parent == NULL ? cur : cur->parent->first,
fsopts->needswap);
root->inode->nlink++; /* count my parent's link */
} else if (cur->child != NULL)
root->inode->nlink++; /* count my child's link */
 
/*
* XXX possibly write file and long symlinks here,
* ensuring that blocks get written before inodes?
* otoh, this isn't a real filesystem, so who
* cares about ordering? :-)
*/
}
if (debug & DEBUG_FS_POPULATE_DIRBUF)
ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap);
 
/*
* pass 2: write out dirbuf, then non-directories at this level
*/
if (debug & DEBUG_FS_POPULATE)
printf("ffs_populate_dir: PASS 2 dir %s\n", dir);
for (cur = root; cur != NULL; cur = cur->next) {
if (cur->inode->flags & FI_WRITTEN)
continue; /* skip hard-linked entries */
cur->inode->flags |= FI_WRITTEN;
 
if ((size_t)snprintf(path, sizeof(path), "%s/%s/%s", cur->root,
cur->path, cur->name) >= sizeof(path))
errx(1, "Pathname too long.");
 
if (cur->child != NULL)
continue; /* child creates own inode */
 
/* build on-disk inode */
if (ffs_opts->version == 1)
membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur,
root, fsopts);
else
membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur,
root, fsopts);
 
if (debug & DEBUG_FS_POPULATE_NODE) {
printf("ffs_populate_dir: writing ino %d, %s",
cur->inode->ino, inode_type(cur->type));
if (cur->inode->nlink > 1)
printf(", nlink %d", cur->inode->nlink);
putchar('\n');
}
 
if (membuf != NULL) {
ffs_write_file(&din, cur->inode->ino, membuf, fsopts);
} else if (S_ISREG(cur->type)) {
ffs_write_file(&din, cur->inode->ino, path, fsopts);
} else {
assert (! S_ISDIR(cur->type));
ffs_write_inode(&din, cur->inode->ino, fsopts);
}
}
 
/*
* pass 3: write out sub-directories
*/
if (debug & DEBUG_FS_POPULATE)
printf("ffs_populate_dir: PASS 3 dir %s\n", dir);
for (cur = root; cur != NULL; cur = cur->next) {
if (cur->child == NULL)
continue;
if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
>= sizeof(path))
errx(1, "Pathname too long.");
if (! ffs_populate_dir(path, cur->child, fsopts))
return (0);
}
 
if (debug & DEBUG_FS_POPULATE)
printf("ffs_populate_dir: DONE dir %s\n", dir);
 
/* cleanup */
if (dirbuf.buf != NULL)
free(dirbuf.buf);
return (1);
}
 
 
static void
ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
{
int isfile, ffd;
char *fbuf, *p;
off_t bufleft, chunk, offset;
ssize_t nread;
struct inode in;
struct buf * bp;
ffs_opt_t *ffs_opts = fsopts->fs_specific;
 
assert (din != NULL);
assert (buf != NULL);
assert (fsopts != NULL);
assert (ffs_opts != NULL);
 
isfile = S_ISREG(DIP(din, mode));
fbuf = NULL;
ffd = -1;
p = NULL;
 
in.i_fs = (struct fs *)fsopts->superblock;
 
if (debug & DEBUG_FS_WRITE_FILE) {
printf(
"ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld",
ino, din, isfile, inode_type(DIP(din, mode) & S_IFMT),
(long long)DIP(din, size));
if (isfile)
printf(", file '%s'\n", (char *)buf);
else
printf(", buffer %p\n", buf);
}
 
in.i_number = ino;
in.i_size = DIP(din, size);
if (ffs_opts->version == 1)
memcpy(&in.i_din.ffs1_din, &din->ffs1_din,
sizeof(in.i_din.ffs1_din));
else
memcpy(&in.i_din.ffs2_din, &din->ffs2_din,
sizeof(in.i_din.ffs2_din));
in.i_fd = fsopts->fd;
 
if (DIP(din, size) == 0)
goto write_inode_and_leave; /* mmm, cheating */
 
if (isfile) {
if ((fbuf = malloc(ffs_opts->bsize)) == NULL)
err(1, "Allocating memory for write buffer");
if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) {
warn("Can't open `%s' for reading", (char *)buf);
goto leave_ffs_write_file;
}
} else {
p = buf;
}
 
chunk = 0;
for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) {
chunk = MIN(bufleft, ffs_opts->bsize);
if (!isfile)
;
else if ((nread = read(ffd, fbuf, chunk)) == -1)
err(EXIT_FAILURE, "Reading `%s', %lld bytes to go",
(char *)buf, (long long)bufleft);
else if (nread != chunk)
errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, "
"read %zd bytes, expected %ju bytes, does "
"metalog size= attribute mismatch source size?",
(char *)buf, (long long)bufleft, nread,
(uintmax_t)chunk);
else
p = fbuf;
offset = DIP(din, size) - bufleft;
if (debug & DEBUG_FS_WRITE_FILE_BLOCK)
printf(
"ffs_write_file: write %p offset %lld size %lld left %lld\n",
p, (long long)offset,
(long long)chunk, (long long)bufleft);
/*
* XXX if holey support is desired, do the check here
*
* XXX might need to write out last bit in fragroundup
* sized chunk. however, ffs_balloc() handles this for us
*/
errno = ffs_balloc(&in, offset, chunk, &bp);
bad_ffs_write_file:
if (errno != 0)
err(1,
"Writing inode %d (%s), bytes %lld + %lld",
ino,
isfile ? (char *)buf :
inode_type(DIP(din, mode) & S_IFMT),
(long long)offset, (long long)chunk);
memcpy(bp->b_data, p, chunk);
errno = bwrite(bp);
if (errno != 0)
goto bad_ffs_write_file;
brelse(bp);
if (!isfile)
p += chunk;
}
write_inode_and_leave:
ffs_write_inode(&in.i_din, in.i_number, fsopts);
 
leave_ffs_write_file:
if (fbuf)
free(fbuf);
if (ffd != -1)
close(ffd);
}
 
 
static void
ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap)
{
doff_t i;
struct direct *de;
uint16_t reclen;
 
assert (dbuf != NULL);
assert (dir != NULL);
printf("ffs_dump_dirbuf: dir %s size %d cur %d\n",
dir, dbuf->size, dbuf->cur);
 
for (i = 0; i < dbuf->size; ) {
de = (struct direct *)(dbuf->buf + i);
reclen = ufs_rw16(de->d_reclen, needswap);
printf(
" inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n",
ufs_rw32(de->d_fileno, needswap),
inode_type(DTTOIF(de->d_type)), i, reclen,
de->d_namlen, de->d_name);
i += reclen;
assert(reclen > 0);
}
}
 
static void
ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
{
struct direct de, *dp;
uint16_t llen, reclen;
u_char *newbuf;
 
assert (dbuf != NULL);
assert (name != NULL);
assert (node != NULL);
/* create direct entry */
(void)memset(&de, 0, sizeof(de));
de.d_fileno = ufs_rw32(node->inode->ino, needswap);
de.d_type = IFTODT(node->type);
de.d_namlen = (uint8_t)strlen(name);
strcpy(de.d_name, name);
reclen = DIRSIZ(0, &de, needswap);
de.d_reclen = ufs_rw16(reclen, needswap);
 
dp = (struct direct *)(dbuf->buf + dbuf->cur);
llen = 0;
if (dp != NULL)
llen = DIRSIZ(0, dp, needswap);
 
if (debug & DEBUG_FS_MAKE_DIRBUF)
printf(
"ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n"
" ino %d type %d reclen %d namlen %d name %.30s\n",
dbuf->size, dbuf->cur, llen,
ufs_rw32(de.d_fileno, needswap), de.d_type, reclen,
de.d_namlen, de.d_name);
 
if (reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) {
if (debug & DEBUG_FS_MAKE_DIRBUF)
printf("ffs_make_dirbuf: growing buf to %d\n",
dbuf->size + DIRBLKSIZ);
if ((newbuf = realloc(dbuf->buf, dbuf->size + DIRBLKSIZ)) == NULL)
err(1, "Allocating memory for directory buffer");
dbuf->buf = newbuf;
dbuf->size += DIRBLKSIZ;
memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
dbuf->cur = dbuf->size - DIRBLKSIZ;
} else if (dp) { /* shrink end of previous */
dp->d_reclen = ufs_rw16(llen,needswap);
dbuf->cur += llen;
}
dp = (struct direct *)(dbuf->buf + dbuf->cur);
memcpy(dp, &de, reclen);
dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap);
}
 
/*
* cribbed from sys/ufs/ffs/ffs_alloc.c
*/
static void
ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
{
char *buf;
struct ufs1_dinode *dp1;
struct ufs2_dinode *dp2, *dip;
struct cg *cgp;
struct fs *fs;
int cg, cgino, i;
daddr_t d;
char sbbuf[FFS_MAXBSIZE];
int32_t initediblk;
ffs_opt_t *ffs_opts = fsopts->fs_specific;
 
assert (dp != NULL);
assert (ino > 0);
assert (fsopts != NULL);
assert (ffs_opts != NULL);
 
fs = (struct fs *)fsopts->superblock;
cg = ino_to_cg(fs, ino);
cgino = ino % fs->fs_ipg;
if (debug & DEBUG_FS_WRITE_INODE)
printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n",
dp, ino, cg, cgino);
 
ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
fsopts);
cgp = (struct cg *)sbbuf;
if (!cg_chkmagic(cgp, fsopts->needswap))
errx(1, "ffs_write_inode: cg %d: bad magic number", cg);
 
assert (isclr(cg_inosused(cgp, fsopts->needswap), cgino));
 
buf = malloc(fs->fs_bsize);
if (buf == NULL)
errx(1, "ffs_write_inode: cg %d: can't alloc inode block", cg);
 
dp1 = (struct ufs1_dinode *)buf;
dp2 = (struct ufs2_dinode *)buf;
 
if (fs->fs_cstotal.cs_nifree == 0)
errx(1, "ffs_write_inode: fs out of inodes for ino %u",
ino);
if (fs->fs_cs(fs, cg).cs_nifree == 0)
errx(1,
"ffs_write_inode: cg %d out of inodes for ino %u",
cg, ino);
setbit(cg_inosused(cgp, fsopts->needswap), cgino);
ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap);
fs->fs_cstotal.cs_nifree--;
fs->fs_cs(fs, cg).cs_nifree--;
if (S_ISDIR(DIP(dp, mode))) {
ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap);
fs->fs_cstotal.cs_ndir++;
fs->fs_cs(fs, cg).cs_ndir++;
}
 
/*
* Initialize inode blocks on the fly for UFS2.
*/
initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap);
if (ffs_opts->version == 2 && cgino + INOPB(fs) > initediblk &&
initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) {
memset(buf, 0, fs->fs_bsize);
dip = (struct ufs2_dinode *)buf;
srandom(time(NULL));
for (i = 0; i < INOPB(fs); i++) {
dip->di_gen = random() / 2 + 1;
dip++;
}
ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs,
cg * fs->fs_ipg + initediblk)),
fs->fs_bsize, buf, fsopts);
initediblk += INOPB(fs);
cgp->cg_initediblk = ufs_rw32(initediblk, fsopts->needswap);
}
 
 
ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
fsopts);
 
/* now write inode */
d = fsbtodb(fs, ino_to_fsba(fs, ino));
ffs_rdfs(d, fs->fs_bsize, buf, fsopts);
if (fsopts->needswap) {
if (ffs_opts->version == 1)
ffs_dinode1_swap(&dp->ffs1_din,
&dp1[ino_to_fsbo(fs, ino)]);
else
ffs_dinode2_swap(&dp->ffs2_din,
&dp2[ino_to_fsbo(fs, ino)]);
} else {
if (ffs_opts->version == 1)
dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din;
else
dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din;
}
ffs_wtfs(d, fs->fs_bsize, buf, fsopts);
free(buf);
}
 
void
panic(const char *fmt, ...)
{
va_list ap;
 
va_start(ap, fmt);
vwarnx(fmt, ap);
va_end(ap);
exit(1);
}
/disk/tools/fs-NetBSD/makefs/ufs_inode.h
0,0 → 1,112
/* $NetBSD: ufs_inode.h,v 1.4 2005/06/23 00:53:16 fvdl Exp $ */
/* From: NetBSD: inode.h,v 1.27 2001/12/18 10:57:23 fvdl Exp $ */
 
/*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)inode.h 8.9 (Berkeley) 5/14/95
*/
 
union dinode {
struct ufs1_dinode ffs1_din;
struct ufs2_dinode ffs2_din;
};
 
struct inode {
ino_t i_number; /* The identity of the inode. */
struct fs *i_fs; /* File system */
union dinode i_din;
int i_fd; /* File descriptor */
uint64_t i_size;
};
 
#define i_ffs1_atime i_din.ffs1_din.di_atime
#define i_ffs1_atimensec i_din.ffs1_din.di_atimensec
#define i_ffs1_blocks i_din.ffs1_din.di_blocks
#define i_ffs1_ctime i_din.ffs1_din.di_ctime
#define i_ffs1_ctimensec i_din.ffs1_din.di_ctimensec
#define i_ffs1_db i_din.ffs1_din.di_db
#define i_ffs1_flags i_din.ffs1_din.di_flags
#define i_ffs1_gen i_din.ffs1_din.di_gen
#define i_ffs11_gid i_din.ffs1_din.di_gid
#define i_ffs1_ib i_din.ffs1_din.di_ib
#define i_ffs1_mode i_din.ffs1_din.di_mode
#define i_ffs1_mtime i_din.ffs1_din.di_mtime
#define i_ffs1_mtimensec i_din.ffs1_din.di_mtimensec
#define i_ffs1_nlink i_din.ffs1_din.di_nlink
#define i_ffs1_rdev i_din.ffs1_din.di_rdev
#define i_ffs1_shortlink i_din.ffs1_din.db
#define i_ffs1_size i_din.ffs1_din.di_size
#define i_ffs1_uid i_din.ffs1_din.di_uid
 
#define i_ffs2_atime i_din.ffs2_din.di_atime
#define i_ffs2_atimensec i_din.ffs2_din.di_atimensec
#define i_ffs2_blocks i_din.ffs2_din.di_blocks
#define i_ffs2_ctime i_din.ffs2_din.di_ctime
#define i_ffs2_ctimensec i_din.ffs2_din.di_ctimensec
#define i_ffs2_birthtime i_din.ffs2_din.di_birthtime
#define i_ffs2_birthnsec i_din.ffs2_din.di_birthnsec
#define i_ffs2_db i_din.ffs2_din.di_db
#define i_ffs2_flags i_din.ffs2_din.di_flags
#define i_ffs2_gen i_din.ffs2_din.di_gen
#define i_ffs21_gid i_din.ffs2_din.di_gid
#define i_ffs2_ib i_din.ffs2_din.di_ib
#define i_ffs2_mode i_din.ffs2_din.di_mode
#define i_ffs2_mtime i_din.ffs2_din.di_mtime
#define i_ffs2_mtimensec i_din.ffs2_din.di_mtimensec
#define i_ffs2_nlink i_din.ffs2_din.di_nlink
#define i_ffs2_rdev i_din.ffs2_din.di_rdev
#define i_ffs2_shortlink i_din.ffs2_din.db
#define i_ffs2_size i_din.ffs2_din.di_size
#define i_ffs2_uid i_din.ffs2_din.di_uid
 
#undef DIP
#define DIP(ip, field) \
(((ip)->i_fs->fs_magic == FS_UFS1_MAGIC) ? \
(ip)->i_ffs1_##field : (ip)->i_ffs2_##field)
 
#define DIP_ASSIGN(ip, field, value) \
do { \
if ((ip)->i_fs->fs_magic == FS_UFS1_MAGIC) \
(ip)->i_ffs1_##field = (value); \
else \
(ip)->i_ffs2_##field = (value); \
} while(0)
 
#define DIP_ADD(ip, field, value) \
do { \
if ((ip)->i_fs->fs_magic == FS_UFS1_MAGIC) \
(ip)->i_ffs1_##field += (value); \
else \
(ip)->i_ffs2_##field += (value); \
} while(0)
/disk/tools/fs-NetBSD/makefs/mtree.h
0,0 → 1,139
/* $NetBSD: mtree.h,v 1.27 2009/04/04 21:49:49 apb Exp $ */
 
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mtree.h 8.1 (Berkeley) 6/6/93
*/
 
#ifndef _MTREE_H_
#define _MTREE_H_
 
#define KEYDEFAULT (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | \
F_TIME | F_TYPE | F_UID | F_FLAGS)
 
#define MISMATCHEXIT 2
 
typedef struct _node {
struct _node *parent, *child; /* up, down */
struct _node *prev, *next; /* left, right */
off_t st_size; /* size */
struct timespec st_mtimespec; /* last modification time */
char *slink; /* symbolic link reference */
uid_t st_uid; /* uid */
gid_t st_gid; /* gid */
#define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
mode_t st_mode; /* mode */
dev_t st_rdev; /* device type */
u_long st_flags; /* flags */
nlink_t st_nlink; /* link count */
u_long cksum; /* check sum */
char *md5digest; /* MD5 digest */
char *rmd160digest; /* RMD-160 digest */
char *sha1digest; /* SHA1 digest */
char *sha256digest; /* SHA256 digest */
char *sha384digest; /* SHA384 digest */
char *sha512digest; /* SHA512 digest */
char *tags; /* tags, comma delimited,
* also with leading and
* trailing commas */
size_t lineno; /* line # entry came from */
 
#define F_CKSUM 0x00000001 /* cksum(1) check sum */
#define F_DEV 0x00000002 /* device type */
#define F_DONE 0x00000004 /* directory done */
#define F_FLAGS 0x00000008 /* file flags */
#define F_GID 0x00000010 /* gid */
#define F_GNAME 0x00000020 /* group name */
#define F_IGN 0x00000040 /* ignore */
#define F_MAGIC 0x00000080 /* name has magic chars */
#define F_MD5 0x00000100 /* MD5 digest */
#define F_MODE 0x00000200 /* mode */
#define F_NLINK 0x00000400 /* number of links */
#define F_OPT 0x00000800 /* existence optional */
#define F_RMD160 0x00001000 /* RMD-160 digest */
#define F_SHA1 0x00002000 /* SHA1 digest */
#define F_SIZE 0x00004000 /* size */
#define F_SLINK 0x00008000 /* symbolic link */
#define F_TAGS 0x00010000 /* tags */
#define F_TIME 0x00020000 /* modification time */
#define F_TYPE 0x00040000 /* file type */
#define F_UID 0x00080000 /* uid */
#define F_UNAME 0x00100000 /* user name */
#define F_VISIT 0x00200000 /* file visited */
#define F_SHA256 0x00800000 /* SHA256 digest */
#define F_SHA384 0x01000000 /* SHA384 digest */
#define F_SHA512 0x02000000 /* SHA512 digest */
 
int flags; /* items set */
 
#define F_BLOCK 0x001 /* block special */
#define F_CHAR 0x002 /* char special */
#define F_DIR 0x004 /* directory */
#define F_FIFO 0x008 /* fifo */
#define F_FILE 0x010 /* regular file */
#define F_LINK 0x020 /* symbolic link */
#define F_SOCK 0x040 /* socket */
#define F_DOOR 0x080 /* door */
int type; /* file type */
 
char name[1]; /* file name (must be last) */
} NODE;
 
 
typedef struct {
char **list;
int count;
} slist_t;
 
 
/*
* prototypes for functions published to other programs which want to use
* the specfile parser but don't want to pull in all of "extern.h"
*/
const char *inotype(u_int);
u_int nodetoino(u_int);
int setup_getid(const char *);
NODE *spec(FILE *);
void free_nodes(NODE *);
char *vispath(const char *);
 
 
#define RP(p) \
((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
(p)->fts_path + 2 : (p)->fts_path)
 
#define UF_MASK ((UF_NODUMP | UF_IMMUTABLE | \
UF_APPEND | UF_OPAQUE) \
& UF_SETTABLE) /* user settable flags */
#define SF_MASK ((SF_ARCHIVED | SF_IMMUTABLE | \
SF_APPEND) & SF_SETTABLE) /* root settable flags */
#define CH_MASK (UF_MASK | SF_MASK) /* all settable flags */
#define SP_FLGS (SF_IMMUTABLE | SF_APPEND) /* special flags */
 
#endif /* _MTREE_H_ */
/disk/tools/fs-NetBSD/makefs/buf.h
0,0 → 1,65
/* $NetBSD: buf.h,v 1.2 2001/11/02 03:12:49 lukem Exp $ */
 
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
 
#ifndef _FFS_BUF_H
#define _FFS_BUF_H
 
#include <sys/param.h>
#include <sys/queue.h>
 
struct buf {
void * b_data;
long b_bufsize;
long b_bcount;
daddr_t b_blkno;
daddr_t b_lblkno;
int b_fd;
struct fs * b_fs;
 
TAILQ_ENTRY(buf) b_tailq;
};
 
void bcleanup(void);
int bread(int, struct fs *, daddr_t, int, struct buf **);
void brelse(struct buf *);
int bwrite(struct buf *);
struct buf * getblk(int, struct fs *, daddr_t, int);
 
#define bdwrite(bp) bwrite(bp)
#define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount)
 
#endif /* _FFS_BUF_H */
/disk/tools/fs-NetBSD/makefs/ffs.h
0,0 → 1,69
/* $NetBSD: ffs.h,v 1.2 2011/10/09 21:33:43 christos Exp $ */
 
/*
* Copyright (c) 2001-2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Luke Mewburn for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
 
#ifndef _FFS_H
#define _FFS_H
 
#include "common.h"
#include "dinode.h"
#include "fs.h"
 
typedef struct {
char label[MAXVOLLEN]; /* volume name/label */
int bsize; /* block size */
int fsize; /* fragment size */
int cpg; /* cylinders per group */
int cpgflg; /* cpg was specified by user */
int density; /* bytes per inode */
int ntracks; /* number of tracks */
int nsectors; /* number of sectors */
int rpm; /* rpm */
int minfree; /* free space threshold */
int optimization; /* optimization (space or time) */
int maxcontig; /* max contiguous blocks to allocate */
int rotdelay; /* rotational delay between blocks */
int maxbpg; /* maximum blocks per file in a cyl group */
int nrpos; /* # of distinguished rotational positions */
int avgfilesize; /* expected average file size */
int avgfpdir; /* expected # of files per directory */
int version; /* filesystem version (1 = FFS, 2 = UFS2) */
int maxbsize; /* maximum extent size */
int maxblkspercg; /* max # of blocks per cylinder group */
/* XXX: support `old' file systems ? */
} ffs_opt_t;
 
#endif /* _FFS_H */
/disk/tools/fs-NetBSD/makefs/dir.h
0,0 → 1,160
/* $NetBSD: dir.h,v 1.21 2009/07/22 04:49:19 dholland Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dir.h 8.5 (Berkeley) 4/27/95
*/
 
#ifndef _UFS_UFS_DIR_H_
#define _UFS_UFS_DIR_H_
 
/*
* Theoretically, directories can be more than 2Gb in length; however, in
* practice this seems unlikely. So, we define the type doff_t as a 32-bit
* quantity to keep down the cost of doing lookup on a 32-bit machine.
*/
#define doff_t int32_t
#define MAXDIRSIZE (0x7fffffff)
 
/*
* A directory consists of some number of blocks of DIRBLKSIZ
* bytes, where DIRBLKSIZ is chosen such that it can be transferred
* to disk in a single atomic operation (e.g. 512 bytes on most machines).
*
* Each DIRBLKSIZ byte block contains some number of directory entry
* structures, which are of variable length. Each directory entry has
* a struct direct at the front of it, containing its inode number,
* the length of the entry, and the length of the name contained in
* the entry. These are followed by the name padded to a 4 byte boundary.
* All names are guaranteed null terminated.
* The maximum length of a name in a directory is FFS_MAXNAMLEN.
*
* The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
* a directory entry. Free space in a directory is represented by
* entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZ bytes
* in a directory block are claimed by the directory entries. This
* usually results in the last entry in a directory having a large
* dp->d_reclen. When entries are deleted from a directory, the
* space is returned to the previous entry in the same directory
* block by increasing its dp->d_reclen. If the first entry of
* a directory block is free, then its dp->d_ino is set to 0.
* Entries other than the first in a directory do not normally have
* dp->d_ino set to 0.
*/
#undef DIRBLKSIZ
#define DIRBLKSIZ DEV_BSIZE
#define FFS_MAXNAMLEN 255
#define APPLEUFS_DIRBLKSIZ 1024
 
#define d_ino d_fileno
struct direct {
u_int32_t d_fileno; /* inode number of entry */
u_int16_t d_reclen; /* length of this record */
u_int8_t d_type; /* file type, see below */
u_int8_t d_namlen; /* length of string in d_name */
char d_name[FFS_MAXNAMLEN + 1];/* name with length <= FFS_MAXNAMLEN */
};
 
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
 
/*
* Convert between stat structure types and directory types.
*/
#define IFTODT(mode) (((mode) & 0170000) >> 12)
#define DTTOIF(dirtype) ((dirtype) << 12)
 
/*
* The DIRSIZ macro gives the minimum record length which will hold
* the directory entry. This requires the amount of space in struct direct
* without the d_name field, plus enough space for the name with a terminating
* null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
*/
#define DIRECTSIZ(namlen) \
((sizeof(struct direct) - (FFS_MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3))
 
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && !(needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#else
#define DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && (needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#endif
 
#define OLDDIRFMT 1
#define NEWDIRFMT 0
 
/*
* Template for manipulating directories. Should use struct direct's,
* but the name field is FFS_MAXNAMLEN - 1, and this just won't do.
*/
struct dirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int8_t dot_type;
u_int8_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int8_t dotdot_type;
u_int8_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
 
/*
* This is the old format of directories, sanz type element.
*/
struct odirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int16_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int16_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
#endif /* !_UFS_UFS_DIR_H_ */
/disk/tools/fs-NetBSD/makefs/ffs_alloc.c
0,0 → 1,603
/* $NetBSD: ffs_alloc.c,v 1.18 2011/03/06 17:08:42 bouyer Exp $ */
/* From: NetBSD: ffs_alloc.c,v 1.50 2001/09/06 02:16:01 lukem Exp */
 
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: ffs_alloc.c,v 1.18 2011/03/06 17:08:42 bouyer Exp $");
#endif /* !__lint */
 
#include <sys/param.h>
#include <sys/time.h>
 
#include <errno.h>
 
#include "common.h"
#include "makefs.h"
 
#include "dinode.h"
#include "ufs_bswap.h"
#include "fs.h"
 
#include "buf.h"
#include "ufs_inode.h"
#include "ffs_extern.h"
 
 
static int scanc(u_int, const u_char *, const u_char *, int);
 
static daddr_t ffs_alloccg(struct inode *, int, daddr_t, int);
static daddr_t ffs_alloccgblk(struct inode *, struct buf *, daddr_t);
static daddr_t ffs_hashalloc(struct inode *, int, daddr_t, int,
daddr_t (*)(struct inode *, int, daddr_t, int));
static int32_t ffs_mapsearch(struct fs *, struct cg *, daddr_t, int);
 
/* in ffs_tables.c */
extern const int inside[], around[];
extern const u_char * const fragtbl[];
 
/*
* Allocate a block in the file system.
*
* The size of the requested block is given, which must be some
* multiple of fs_fsize and <= fs_bsize.
* A preference may be optionally specified. If a preference is given
* the following hierarchy is used to allocate a block:
* 1) allocate the requested block.
* 2) allocate a rotationally optimal block in the same cylinder.
* 3) allocate a block in the same cylinder group.
* 4) quadradically rehash into other cylinder groups, until an
* available block is located.
* If no block preference is given the following hierarchy is used
* to allocate a block:
* 1) allocate a block in the cylinder group that contains the
* inode for the file.
* 2) quadradically rehash into other cylinder groups, until an
* available block is located.
*/
int
ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size,
daddr_t *bnp)
{
struct fs *fs = ip->i_fs;
daddr_t bno;
int cg;
*bnp = 0;
if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) {
errx(1, "ffs_alloc: bad size: bsize %d size %d",
fs->fs_bsize, size);
}
if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
goto nospace;
if (bpref >= fs->fs_size)
bpref = 0;
if (bpref == 0)
cg = ino_to_cg(fs, ip->i_number);
else
cg = dtog(fs, bpref);
bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg);
if (bno > 0) {
DIP_ADD(ip, blocks, size / DEV_BSIZE);
*bnp = bno;
return (0);
}
nospace:
return (ENOSPC);
}
 
/*
* Select the desired position for the next block in a file. The file is
* logically divided into sections. The first section is composed of the
* direct blocks. Each additional section contains fs_maxbpg blocks.
*
* If no blocks have been allocated in the first section, the policy is to
* request a block in the same cylinder group as the inode that describes
* the file. If no blocks have been allocated in any other section, the
* policy is to place the section in a cylinder group with a greater than
* average number of free blocks. An appropriate cylinder group is found
* by using a rotor that sweeps the cylinder groups. When a new group of
* blocks is needed, the sweep begins in the cylinder group following the
* cylinder group from which the previous allocation was made. The sweep
* continues until a cylinder group with greater than the average number
* of free blocks is found. If the allocation is for the first block in an
* indirect block, the information on the previous allocation is unavailable;
* here a best guess is made based upon the logical block number being
* allocated.
*
* If a section is already partially allocated, the policy is to
* contiguously allocate fs_maxcontig blocks. The end of one of these
* contiguous blocks and the beginning of the next is physically separated
* so that the disk head will be in transit between them for at least
* fs_rotdelay milliseconds. This is to allow time for the processor to
* schedule another I/O transfer.
*/
/* XXX ondisk32 */
daddr_t
ffs_blkpref_ufs1(struct inode *ip, daddr_t lbn, int indx, int32_t *bap)
{
struct fs *fs;
int cg;
int avgbfree, startcg;
 
fs = ip->i_fs;
if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
if (lbn < NDADDR + NINDIR(fs)) {
cg = ino_to_cg(fs, ip->i_number);
return (fs->fs_fpg * cg + fs->fs_frag);
}
/*
* Find a cylinder with greater than average number of
* unused data blocks.
*/
if (indx == 0 || bap[indx - 1] == 0)
startcg =
ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
else
startcg = dtog(fs,
ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
startcg %= fs->fs_ncg;
avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
for (cg = startcg; cg < fs->fs_ncg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
return (fs->fs_fpg * cg + fs->fs_frag);
for (cg = 0; cg <= startcg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
return (fs->fs_fpg * cg + fs->fs_frag);
return (0);
}
/*
* We just always try to lay things out contiguously.
*/
return ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
}
 
daddr_t
ffs_blkpref_ufs2(ip, lbn, indx, bap)
struct inode *ip;
daddr_t lbn;
int indx;
int64_t *bap;
{
struct fs *fs;
int cg;
int avgbfree, startcg;
 
fs = ip->i_fs;
if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
if (lbn < NDADDR + NINDIR(fs)) {
cg = ino_to_cg(fs, ip->i_number);
return (fs->fs_fpg * cg + fs->fs_frag);
}
/*
* Find a cylinder with greater than average number of
* unused data blocks.
*/
if (indx == 0 || bap[indx - 1] == 0)
startcg =
ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
else
startcg = dtog(fs,
ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
startcg %= fs->fs_ncg;
avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
for (cg = startcg; cg < fs->fs_ncg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
return (fs->fs_fpg * cg + fs->fs_frag);
}
for (cg = 0; cg < startcg; cg++)
if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
return (fs->fs_fpg * cg + fs->fs_frag);
}
return (0);
}
/*
* We just always try to lay things out contiguously.
*/
return ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
}
 
/*
* Implement the cylinder overflow algorithm.
*
* The policy implemented by this algorithm is:
* 1) allocate the block in its requested cylinder group.
* 2) quadradically rehash on the cylinder group number.
* 3) brute force search for a free block.
*
* `size': size for data blocks, mode for inodes
*/
/*VARARGS5*/
static daddr_t
ffs_hashalloc(struct inode *ip, int cg, daddr_t pref, int size,
daddr_t (*allocator)(struct inode *, int, daddr_t, int))
{
struct fs *fs;
daddr_t result;
int i, icg = cg;
 
fs = ip->i_fs;
/*
* 1: preferred cylinder group
*/
result = (*allocator)(ip, cg, pref, size);
if (result)
return (result);
/*
* 2: quadratic rehash
*/
for (i = 1; i < fs->fs_ncg; i *= 2) {
cg += i;
if (cg >= fs->fs_ncg)
cg -= fs->fs_ncg;
result = (*allocator)(ip, cg, 0, size);
if (result)
return (result);
}
/*
* 3: brute force search
* Note that we start at i == 2, since 0 was checked initially,
* and 1 is always checked in the quadratic rehash.
*/
cg = (icg + 2) % fs->fs_ncg;
for (i = 2; i < fs->fs_ncg; i++) {
result = (*allocator)(ip, cg, 0, size);
if (result)
return (result);
cg++;
if (cg == fs->fs_ncg)
cg = 0;
}
return (0);
}
 
/*
* Determine whether a block can be allocated.
*
* Check to see if a block of the appropriate size is available,
* and if it is, allocate it.
*/
static daddr_t
ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
{
struct cg *cgp;
struct buf *bp;
daddr_t bno, blkno;
int error, frags, allocsiz, i;
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
 
if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
return (0);
error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, &bp);
if (error) {
brelse(bp);
return (0);
}
cgp = (struct cg *)bp->b_data;
if (!cg_chkmagic(cgp, needswap) ||
(cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
brelse(bp);
return (0);
}
if (size == fs->fs_bsize) {
bno = ffs_alloccgblk(ip, bp, bpref);
bdwrite(bp);
return (bno);
}
/*
* check to see if any fragments are already available
* allocsiz is the size which will be allocated, hacking
* it down to a smaller size if necessary
*/
frags = numfrags(fs, size);
for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
if (cgp->cg_frsum[allocsiz] != 0)
break;
if (allocsiz == fs->fs_frag) {
/*
* no fragments were available, so a block will be
* allocated, and hacked up
*/
if (cgp->cg_cs.cs_nbfree == 0) {
brelse(bp);
return (0);
}
bno = ffs_alloccgblk(ip, bp, bpref);
bpref = dtogd(fs, bno);
for (i = frags; i < fs->fs_frag; i++)
setbit(cg_blksfree(cgp, needswap), bpref + i);
i = fs->fs_frag - frags;
ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
fs->fs_cstotal.cs_nffree += i;
fs->fs_cs(fs, cg).cs_nffree += i;
fs->fs_fmod = 1;
ufs_add32(cgp->cg_frsum[i], 1, needswap);
bdwrite(bp);
return (bno);
}
bno = ffs_mapsearch(fs, cgp, bpref, allocsiz);
for (i = 0; i < frags; i++)
clrbit(cg_blksfree(cgp, needswap), bno + i);
ufs_add32(cgp->cg_cs.cs_nffree, -frags, needswap);
fs->fs_cstotal.cs_nffree -= frags;
fs->fs_cs(fs, cg).cs_nffree -= frags;
fs->fs_fmod = 1;
ufs_add32(cgp->cg_frsum[allocsiz], -1, needswap);
if (frags != allocsiz)
ufs_add32(cgp->cg_frsum[allocsiz - frags], 1, needswap);
blkno = cg * fs->fs_fpg + bno;
bdwrite(bp);
return blkno;
}
 
/*
* Allocate a block in a cylinder group.
*
* This algorithm implements the following policy:
* 1) allocate the requested block.
* 2) allocate a rotationally optimal block in the same cylinder.
* 3) allocate the next available block on the block rotor for the
* specified cylinder group.
* Note that this routine only allocates fs_bsize blocks; these
* blocks may be fragmented by the routine that allocates them.
*/
static daddr_t
ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
{
struct cg *cgp;
daddr_t blkno;
int32_t bno;
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
u_int8_t *blksfree;
 
cgp = (struct cg *)bp->b_data;
blksfree = cg_blksfree(cgp, needswap);
if (bpref == 0 || dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) {
bpref = ufs_rw32(cgp->cg_rotor, needswap);
} else {
bpref = blknum(fs, bpref);
bno = dtogd(fs, bpref);
/*
* if the requested block is available, use it
*/
if (ffs_isblock(fs, blksfree, fragstoblks(fs, bno)))
goto gotit;
}
/*
* Take the next available one in this cylinder group.
*/
bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag);
if (bno < 0)
return (0);
cgp->cg_rotor = ufs_rw32(bno, needswap);
gotit:
blkno = fragstoblks(fs, bno);
ffs_clrblock(fs, blksfree, (long)blkno);
ffs_clusteracct(fs, cgp, blkno, -1);
ufs_add32(cgp->cg_cs.cs_nbfree, -1, needswap);
fs->fs_cstotal.cs_nbfree--;
fs->fs_cs(fs, ufs_rw32(cgp->cg_cgx, needswap)).cs_nbfree--;
fs->fs_fmod = 1;
blkno = ufs_rw32(cgp->cg_cgx, needswap) * fs->fs_fpg + bno;
return (blkno);
}
 
/*
* Free a block or fragment.
*
* The specified block or fragment is placed back in the
* free map. If a fragment is deallocated, a possible
* block reassembly is checked.
*/
void
ffs_blkfree(struct inode *ip, daddr_t bno, long size)
{
struct cg *cgp;
struct buf *bp;
int32_t fragno, cgbno;
int i, error, cg, blk, frags, bbase;
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
 
if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 ||
fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) {
errx(1, "blkfree: bad size: bno %lld bsize %d size %ld",
(long long)bno, fs->fs_bsize, size);
}
cg = dtog(fs, bno);
if (bno >= fs->fs_size) {
warnx("bad block %lld, ino %llu", (long long)bno,
(unsigned long long)ip->i_number);
return;
}
error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, &bp);
if (error) {
brelse(bp);
return;
}
cgp = (struct cg *)bp->b_data;
if (!cg_chkmagic(cgp, needswap)) {
brelse(bp);
return;
}
cgbno = dtogd(fs, bno);
if (size == fs->fs_bsize) {
fragno = fragstoblks(fs, cgbno);
if (!ffs_isfreeblock(fs, cg_blksfree(cgp, needswap), fragno)) {
errx(1, "blkfree: freeing free block %lld",
(long long)bno);
}
ffs_setblock(fs, cg_blksfree(cgp, needswap), fragno);
ffs_clusteracct(fs, cgp, fragno, 1);
ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
fs->fs_cstotal.cs_nbfree++;
fs->fs_cs(fs, cg).cs_nbfree++;
} else {
bbase = cgbno - fragnum(fs, cgbno);
/*
* decrement the counts associated with the old frags
*/
blk = blkmap(fs, cg_blksfree(cgp, needswap), bbase);
ffs_fragacct(fs, blk, cgp->cg_frsum, -1, needswap);
/*
* deallocate the fragment
*/
frags = numfrags(fs, size);
for (i = 0; i < frags; i++) {
if (isset(cg_blksfree(cgp, needswap), cgbno + i)) {
errx(1, "blkfree: freeing free frag: block %lld",
(long long)(cgbno + i));
}
setbit(cg_blksfree(cgp, needswap), cgbno + i);
}
ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
fs->fs_cstotal.cs_nffree += i;
fs->fs_cs(fs, cg).cs_nffree += i;
/*
* add back in counts associated with the new frags
*/
blk = blkmap(fs, cg_blksfree(cgp, needswap), bbase);
ffs_fragacct(fs, blk, cgp->cg_frsum, 1, needswap);
/*
* if a complete block has been reassembled, account for it
*/
fragno = fragstoblks(fs, bbase);
if (ffs_isblock(fs, cg_blksfree(cgp, needswap), fragno)) {
ufs_add32(cgp->cg_cs.cs_nffree, -fs->fs_frag, needswap);
fs->fs_cstotal.cs_nffree -= fs->fs_frag;
fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
ffs_clusteracct(fs, cgp, fragno, 1);
ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
fs->fs_cstotal.cs_nbfree++;
fs->fs_cs(fs, cg).cs_nbfree++;
}
}
fs->fs_fmod = 1;
bdwrite(bp);
}
 
 
static int
scanc(u_int size, const u_char *cp, const u_char table[], int mask)
{
const u_char *end = &cp[size];
 
while (cp < end && (table[*cp] & mask) == 0)
cp++;
return (end - cp);
}
 
/*
* Find a block of the specified size in the specified cylinder group.
*
* It is a panic if a request is made to find a block if none are
* available.
*/
static int32_t
ffs_mapsearch(struct fs *fs, struct cg *cgp, daddr_t bpref, int allocsiz)
{
int32_t bno;
int start, len, loc, i;
int blk, field, subfield, pos;
int ostart, olen;
const int needswap = UFS_FSNEEDSWAP(fs);
 
/*
* find the fragment by searching through the free block
* map for an appropriate bit pattern
*/
if (bpref)
start = dtogd(fs, bpref) / NBBY;
else
start = ufs_rw32(cgp->cg_frotor, needswap) / NBBY;
len = howmany(fs->fs_fpg, NBBY) - start;
ostart = start;
olen = len;
loc = scanc((u_int)len,
(const u_char *)&cg_blksfree(cgp, needswap)[start],
(const u_char *)fragtbl[fs->fs_frag],
(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
if (loc == 0) {
len = start + 1;
start = 0;
loc = scanc((u_int)len,
(const u_char *)&cg_blksfree(cgp, needswap)[0],
(const u_char *)fragtbl[fs->fs_frag],
(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
if (loc == 0) {
errx(1,
"ffs_alloccg: map corrupted: start %d len %d offset %d %ld",
ostart, olen,
ufs_rw32(cgp->cg_freeoff, needswap),
(long)cg_blksfree(cgp, needswap) - (long)cgp);
/* NOTREACHED */
}
}
bno = (start + len - loc) * NBBY;
cgp->cg_frotor = ufs_rw32(bno, needswap);
/*
* found the byte in the map
* sift through the bits to find the selected frag
*/
for (i = bno + NBBY; bno < i; bno += fs->fs_frag) {
blk = blkmap(fs, cg_blksfree(cgp, needswap), bno);
blk <<= 1;
field = around[allocsiz];
subfield = inside[allocsiz];
for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) {
if ((blk & field) == subfield)
return (bno + pos);
field <<= 1;
subfield <<= 1;
}
}
errx(1, "ffs_alloccg: block not in map: bno %lld", (long long)bno);
return (-1);
}
/disk/tools/fs-NetBSD/makefs/ffs_balloc.c
0,0 → 1,585
/* $NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $ */
/* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
 
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $");
#endif /* !__lint */
 
#include <sys/param.h>
#include <sys/time.h>
 
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "common.h"
#include "makefs.h"
 
#include "dinode.h"
#include "ufs_bswap.h"
#include "fs.h"
 
#include "buf.h"
#include "ufs_inode.h"
#include "ffs_extern.h"
 
static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
 
/*
* Balloc defines the structure of file system storage
* by allocating the physical blocks on a device given
* the inode and the logical block number in a file.
*
* Assume: flags == B_SYNC | B_CLRBUF
*/
 
int
ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
{
if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
else
return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
}
 
static int
ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
{
daddr_t lbn, lastlbn;
int size;
int32_t nb;
struct buf *bp, *nbp;
struct fs *fs = ip->i_fs;
struct indir indirs[NIADDR + 2];
daddr_t newb, pref;
int32_t *bap;
int osize, nsize, num, i, error;
int32_t *allocblk, allociblk[NIADDR + 1];
int32_t *allocib;
const int needswap = UFS_FSNEEDSWAP(fs);
 
lbn = lblkno(fs, offset);
size = blkoff(fs, offset) + bufsize;
if (bpp != NULL) {
*bpp = NULL;
}
 
assert(size <= fs->fs_bsize);
if (lbn < 0)
return (EFBIG);
 
/*
* If the next write will extend the file into a new block,
* and the file is currently composed of a fragment
* this fragment has to be extended to be a full block.
*/
 
lastlbn = lblkno(fs, ip->i_ffs1_size);
if (lastlbn < NDADDR && lastlbn < lbn) {
nb = lastlbn;
osize = blksize(fs, ip, nb);
if (osize < fs->fs_bsize && osize > 0) {
warnx("need to ffs_realloccg; not supported!");
abort();
}
}
 
/*
* The first NDADDR blocks are direct blocks
*/
 
if (lbn < NDADDR) {
nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
 
/*
* The block is an already-allocated direct block
* and the file already extends past this block,
* thus this must be a whole block.
* Just read the block (if requested).
*/
 
if (bpp != NULL) {
error = bread(ip->i_fd, ip->i_fs, lbn,
fs->fs_bsize, bpp);
if (error) {
brelse(*bpp);
return (error);
}
}
return (0);
}
if (nb != 0) {
 
/*
* Consider need to reallocate a fragment.
*/
 
osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
nsize = fragroundup(fs, size);
if (nsize <= osize) {
 
/*
* The existing block is already
* at least as big as we want.
* Just read the block (if requested).
*/
 
if (bpp != NULL) {
error = bread(ip->i_fd, ip->i_fs, lbn,
osize, bpp);
if (error) {
brelse(*bpp);
return (error);
}
}
return 0;
} else {
warnx("need to ffs_realloccg; not supported!");
abort();
}
} else {
 
/*
* the block was not previously allocated,
* allocate a new block or fragment.
*/
 
if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
nsize = fragroundup(fs, size);
else
nsize = fs->fs_bsize;
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs1(ip, lbn, (int)lbn,
&ip->i_ffs1_db[0]),
nsize, &newb);
if (error)
return (error);
if (bpp != NULL) {
bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
bp->b_blkno = fsbtodb(fs, newb);
clrbuf(bp);
*bpp = bp;
}
}
ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
return (0);
}
 
/*
* Determine the number of levels of indirection.
*/
 
pref = 0;
if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
return (error);
 
if (num < 1) {
warnx("ffs_balloc: ufs_getlbns returned indirect block");
abort();
}
 
/*
* Fetch the first indirect block allocating if necessary.
*/
 
--num;
nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
allocib = NULL;
allocblk = allociblk;
if (nb == 0) {
pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error)
return error;
nb = newb;
*allocblk++ = nb;
bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
bp->b_blkno = fsbtodb(fs, nb);
clrbuf(bp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(bp)) != 0)
return error;
allocib = &ip->i_ffs1_ib[indirs[0].in_off];
*allocib = ufs_rw32((int32_t)nb, needswap);
}
 
/*
* Fetch through the indirect blocks, allocating as necessary.
*/
 
for (i = 1;;) {
error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
fs->fs_bsize, &bp);
if (error) {
brelse(bp);
return error;
}
bap = (int32_t *)bp->b_data;
nb = ufs_rw32(bap[indirs[i].in_off], needswap);
if (i == num)
break;
i++;
if (nb != 0) {
brelse(bp);
continue;
}
if (pref == 0)
pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp);
return error;
}
nb = newb;
*allocblk++ = nb;
nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
fs->fs_bsize);
nbp->b_blkno = fsbtodb(fs, nb);
clrbuf(nbp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
 
if ((error = bwrite(nbp)) != 0) {
brelse(bp);
return error;
}
bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
 
bwrite(bp);
}
 
/*
* Get the data block, allocating if necessary.
*/
 
if (nb == 0) {
pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp);
return error;
}
nb = newb;
*allocblk++ = nb;
if (bpp != NULL) {
nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
nbp->b_blkno = fsbtodb(fs, nb);
clrbuf(nbp);
*bpp = nbp;
}
bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
 
/*
* If required, write synchronously, otherwise use
* delayed write.
*/
bwrite(bp);
return (0);
}
brelse(bp);
if (bpp != NULL) {
error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
if (error) {
brelse(nbp);
return error;
}
*bpp = nbp;
}
return (0);
}
 
static int
ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
{
daddr_t lbn, lastlbn;
int size;
struct buf *bp, *nbp;
struct fs *fs = ip->i_fs;
struct indir indirs[NIADDR + 2];
daddr_t newb, pref, nb;
int64_t *bap;
int osize, nsize, num, i, error;
int64_t *allocblk, allociblk[NIADDR + 1];
int64_t *allocib;
const int needswap = UFS_FSNEEDSWAP(fs);
 
lbn = lblkno(fs, offset);
size = blkoff(fs, offset) + bufsize;
if (bpp != NULL) {
*bpp = NULL;
}
 
assert(size <= fs->fs_bsize);
if (lbn < 0)
return (EFBIG);
 
/*
* If the next write will extend the file into a new block,
* and the file is currently composed of a fragment
* this fragment has to be extended to be a full block.
*/
 
lastlbn = lblkno(fs, ip->i_ffs2_size);
if (lastlbn < NDADDR && lastlbn < lbn) {
nb = lastlbn;
osize = blksize(fs, ip, nb);
if (osize < fs->fs_bsize && osize > 0) {
warnx("need to ffs_realloccg; not supported!");
abort();
}
}
 
/*
* The first NDADDR blocks are direct blocks
*/
 
if (lbn < NDADDR) {
nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
 
/*
* The block is an already-allocated direct block
* and the file already extends past this block,
* thus this must be a whole block.
* Just read the block (if requested).
*/
 
if (bpp != NULL) {
error = bread(ip->i_fd, ip->i_fs, lbn,
fs->fs_bsize, bpp);
if (error) {
brelse(*bpp);
return (error);
}
}
return (0);
}
if (nb != 0) {
 
/*
* Consider need to reallocate a fragment.
*/
 
osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
nsize = fragroundup(fs, size);
if (nsize <= osize) {
 
/*
* The existing block is already
* at least as big as we want.
* Just read the block (if requested).
*/
 
if (bpp != NULL) {
error = bread(ip->i_fd, ip->i_fs, lbn,
osize, bpp);
if (error) {
brelse(*bpp);
return (error);
}
}
return 0;
} else {
warnx("need to ffs_realloccg; not supported!");
abort();
}
} else {
 
/*
* the block was not previously allocated,
* allocate a new block or fragment.
*/
 
if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
nsize = fragroundup(fs, size);
else
nsize = fs->fs_bsize;
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn,
&ip->i_ffs2_db[0]),
nsize, &newb);
if (error)
return (error);
if (bpp != NULL) {
bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
bp->b_blkno = fsbtodb(fs, newb);
clrbuf(bp);
*bpp = bp;
}
}
ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
return (0);
}
 
/*
* Determine the number of levels of indirection.
*/
 
pref = 0;
if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
return (error);
 
if (num < 1) {
warnx("ffs_balloc: ufs_getlbns returned indirect block");
abort();
}
 
/*
* Fetch the first indirect block allocating if necessary.
*/
 
--num;
nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
allocib = NULL;
allocblk = allociblk;
if (nb == 0) {
pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error)
return error;
nb = newb;
*allocblk++ = nb;
bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
bp->b_blkno = fsbtodb(fs, nb);
clrbuf(bp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(bp)) != 0)
return error;
allocib = &ip->i_ffs2_ib[indirs[0].in_off];
*allocib = ufs_rw64(nb, needswap);
}
 
/*
* Fetch through the indirect blocks, allocating as necessary.
*/
 
for (i = 1;;) {
error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
fs->fs_bsize, &bp);
if (error) {
brelse(bp);
return error;
}
bap = (int64_t *)bp->b_data;
nb = ufs_rw64(bap[indirs[i].in_off], needswap);
if (i == num)
break;
i++;
if (nb != 0) {
brelse(bp);
continue;
}
if (pref == 0)
pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp);
return error;
}
nb = newb;
*allocblk++ = nb;
nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
fs->fs_bsize);
nbp->b_blkno = fsbtodb(fs, nb);
clrbuf(nbp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
 
if ((error = bwrite(nbp)) != 0) {
brelse(bp);
return error;
}
bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
 
bwrite(bp);
}
 
/*
* Get the data block, allocating if necessary.
*/
 
if (nb == 0) {
pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
if (error) {
brelse(bp);
return error;
}
nb = newb;
*allocblk++ = nb;
if (bpp != NULL) {
nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
nbp->b_blkno = fsbtodb(fs, nb);
clrbuf(nbp);
*bpp = nbp;
}
bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
 
/*
* If required, write synchronously, otherwise use
* delayed write.
*/
bwrite(bp);
return (0);
}
brelse(bp);
if (bpp != NULL) {
error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
if (error) {
brelse(nbp);
return error;
}
*bpp = nbp;
}
return (0);
}
/disk/tools/fs-NetBSD/makefs/Makefile
0,0 → 1,37
#
# Makefile for makefs utility
#
 
BUILD = ../../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = makefs.c walk.c ffs.c mkfs.c ffs_bswap.c ffs_balloc.c \
ufs_bmap.c ffs_alloc.c ffs_subr.c ffs_tables.c buf.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = NetBSD-makefs
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/tools/fs-NetBSD/makefs/ufs_bmap.c
0,0 → 1,146
/* $NetBSD: ufs_bmap.c,v 1.16 2005/10/08 03:21:17 chs Exp $ */
/* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */
 
/*
* Copyright (c) 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95
*/
 
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
 
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(__lint)
__RCSID("$NetBSD: ufs_bmap.c,v 1.16 2005/10/08 03:21:17 chs Exp $");
#endif /* !__lint */
 
#include <sys/param.h>
#include <sys/time.h>
 
#include <assert.h>
#include <errno.h>
#include <strings.h>
 
//#include "makefs.h"
 
#include "common.h"
#include "dinode.h"
#include "ufs_bswap.h"
#include "fs.h"
 
#include "ufs_inode.h"
#include "ffs_extern.h"
 
/*
* Create an array of logical block number/offset pairs which represent the
* path of indirect blocks required to access a data block. The first "pair"
* contains the logical block number of the appropriate single, double or
* triple indirect block and the offset into the inode indirect block array.
* Note, the logical block number of the inode single/double/triple indirect
* block appears twice in the array, once with the offset into the i_ffs_ib and
* once with the offset into the page itself.
*/
int
ufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump)
{
daddr_t metalbn, realbn;
int64_t blockcnt;
int lbc;
int i, numlevels, off;
u_long lognindir;
 
lognindir = ffs(NINDIR(ip->i_fs)) - 1;
if (nump)
*nump = 0;
numlevels = 0;
realbn = bn;
if ((long)bn < 0)
bn = -(long)bn;
 
assert (bn >= NDADDR);
 
/*
* Determine the number of levels of indirection. After this loop
* is done, blockcnt indicates the number of data blocks possible
* at the given level of indirection, and NIADDR - i is the number
* of levels of indirection needed to locate the requested block.
*/
 
bn -= NDADDR;
for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) {
if (i == 0)
return (EFBIG);
 
lbc += lognindir;
blockcnt = (int64_t)1 << lbc;
 
if (bn < blockcnt)
break;
}
 
/* Calculate the address of the first meta-block. */
metalbn = -((realbn >= 0 ? realbn : -realbn) - bn + NIADDR - i);
 
/*
* At each iteration, off is the offset into the bap array which is
* an array of disk addresses at the current level of indirection.
* The logical block number and the offset in that block are stored
* into the argument array.
*/
ap->in_lbn = metalbn;
ap->in_off = off = NIADDR - i;
ap->in_exists = 0;
ap++;
for (++numlevels; i <= NIADDR; i++) {
/* If searching for a meta-data block, quit when found. */
if (metalbn == realbn)
break;
 
lbc -= lognindir;
blockcnt = (int64_t)1 << lbc;
off = (bn >> lbc) & (NINDIR(ip->i_fs) - 1);
 
++numlevels;
ap->in_lbn = metalbn;
ap->in_off = off;
ap->in_exists = 0;
++ap;
 
metalbn -= -1 + (off << lbc);
}
if (nump)
*nump = numlevels;
return (0);
}
/disk/tools/fs-NetBSD/makefs/common.h
0,0 → 1,37
/*
* common.h -- common types, etc.
*/
 
 
#ifndef _COMMON_H_
#define _COMMON_H_
 
 
#include <errno.h>
#include <err.h>
 
 
#ifdef __linux__
 
#include <byteswap.h>
 
#define bswap16(a) bswap_16(a)
#define bswap32(a) bswap_32(a)
#define bswap64(a) bswap_64(a)
 
#endif
 
 
typedef unsigned long long uintmax_t;
 
typedef unsigned long long uint64_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
 
 
#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */
#define MAXQUOTAS 2
 
 
#endif /* _COMMON_H_ */
/disk/tools/fs-NetBSD/dsklbl/disklabel.h
0,0 → 1,62
/*
* disklabel.h -- structure of the disklabel
*/
 
 
#ifndef _DISKLABEL_H_
#define _DISKLABEL_H_
 
 
#define DSKMAGIC 0x82564557
#define NTYPENAME 16
#define NPACKNAME 16
#define NDDATA 5
#define NSPARE 5
#define MAXPARTS 16
#define PADSIZE 108
 
 
typedef struct {
uint32_t p_size; /* number of sectors in partition */
uint32_t p_offset; /* starting sector */
uint32_t p_fsize; /* filesystem basic fragment size */
uint8_t p_fstype; /* filesystem type */
uint8_t p_frag; /* filesystem fragments per block */
uint16_t p_cpg; /* filesystem cylinders per group */
} Partition;
 
typedef struct {
uint32_t d_magic; /* magic number */
uint16_t d_type; /* drive type */
uint16_t d_subtype; /* controller, d_type specific */
char d_typename[NTYPENAME]; /* type name */
char d_packname[NPACKNAME]; /* pack identifier */
uint32_t d_secsize; /* bytes per sector */
uint32_t d_nsectors; /* data sectors per track */
uint32_t d_ntracks; /* tracks per cylinder */
uint32_t d_ncylinders; /* data cylinders per unit */
uint32_t d_secpercyl; /* data sectors per cylinder */
uint32_t d_secperunit; /* data sectors per unit */
uint16_t d_sparespertrack; /* spare sectors per track */
uint16_t d_sparespercyl; /* spare sectors per cylinder */
uint32_t d_acylinders; /* alternative cylinders per unit */
uint16_t d_rpm; /* rotational speed */
uint16_t d_interleave; /* hardware sector interleave */
uint16_t d_trackskew; /* sector 0 skew, per track */
uint16_t d_cylskew; /* sector 0 skew, per cylinder */
uint32_t d_headswitch; /* head switch time, usec */
uint32_t d_trkseek; /* track-to-track seek, usec */
uint32_t d_flags; /* generic flags */
uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
uint32_t d_spare[NSPARE]; /* reserved for future use */
uint32_t d_magic2; /* the magic number again */
uint16_t d_checksum; /* xor of data incl partitions */
uint16_t d_npartitions; /* number of partitions */
uint32_t d_bbsize; /* size of boot area at sector 0, bytes */
uint32_t d_sbsize; /* size of filesystem superblock, bytes */
Partition d_parts[MAXPARTS]; /* the partition table */
uint8_t d_pad[PADSIZE]; /* pad up to sector size */
} DiskLabel;
 
 
#endif /* _DISKLABEL_H_ */
/disk/tools/fs-NetBSD/dsklbl/types.h
0,0 → 1,15
/*
* types.h -- additional types
*/
 
 
#ifndef _TYPES_H_
#define _TYPES_H_
 
 
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
 
 
#endif /* _TYPES_H_ */
/disk/tools/fs-NetBSD/dsklbl/dsklbl.c
0,0 → 1,690
/*
* dsklbl.c -- show or write a disklabel onto a NetBSD partition
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
 
#include "types.h"
#include "disklabel.h"
 
 
/**************************************************************/
 
 
#define SSIZE 512 /* disk sector size in bytes */
#define BSIZE 8192 /* disk block size in bytes */
 
 
/**************************************************************/
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
printf("Error: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
exit(1);
}
 
 
/**************************************************************/
 
 
unsigned int read4FromEco(unsigned char *p) {
return (unsigned int) p[0] << 24 |
(unsigned int) p[1] << 16 |
(unsigned int) p[2] << 8 |
(unsigned int) p[3] << 0;
}
 
 
void write4ToEco(unsigned char *p, unsigned int data) {
p[0] = data >> 24;
p[1] = data >> 16;
p[2] = data >> 8;
p[3] = data >> 0;
}
 
 
unsigned short read2FromEco(unsigned char *p) {
return (unsigned short) p[0] << 8 |
(unsigned short) p[1] << 0;
}
 
 
void write2ToEco(unsigned char *p, unsigned short data) {
p[0] = data >> 8;
p[1] = data >> 0;
}
 
 
void conv4FromEcoToX86(unsigned char *p) {
unsigned int data;
 
data = read4FromEco(p);
* (unsigned int *) p = data;
}
 
 
void conv4FromX86ToEco(unsigned char *p) {
unsigned int data;
 
data = * (unsigned int *) p;
write4ToEco(p, data);
}
 
 
void conv2FromEcoToX86(unsigned char *p) {
unsigned short data;
 
data = read2FromEco(p);
* (unsigned short *) p = data;
}
 
 
void conv2FromX86ToEco(unsigned char *p) {
unsigned short data;
 
data = * (unsigned short *) p;
write2ToEco(p, data);
}
 
 
/**************************************************************/
 
 
uint16_t chksum(DiskLabel *lp, int numParts) {
uint16_t *start;
uint16_t *end;
uint16_t sum;
 
start = (uint16_t *) lp;
end = (uint16_t *) &lp->d_parts[numParts];
sum = 0;
while (start < end) {
sum ^= *start++;
}
return sum;
}
 
 
/**************************************************************/
 
 
void dlFromEcoToX86(DiskLabel *lp) {
int i;
int numParts;
 
conv4FromEcoToX86((unsigned char *) &lp->d_magic);
conv2FromEcoToX86((unsigned char *) &lp->d_type);
conv2FromEcoToX86((unsigned char *) &lp->d_subtype);
conv4FromEcoToX86((unsigned char *) &lp->d_secsize);
conv4FromEcoToX86((unsigned char *) &lp->d_nsectors);
conv4FromEcoToX86((unsigned char *) &lp->d_ntracks);
conv4FromEcoToX86((unsigned char *) &lp->d_ncylinders);
conv4FromEcoToX86((unsigned char *) &lp->d_secpercyl);
conv4FromEcoToX86((unsigned char *) &lp->d_secperunit);
conv2FromEcoToX86((unsigned char *) &lp->d_sparespertrack);
conv2FromEcoToX86((unsigned char *) &lp->d_sparespercyl);
conv4FromEcoToX86((unsigned char *) &lp->d_acylinders);
conv2FromEcoToX86((unsigned char *) &lp->d_rpm);
conv2FromEcoToX86((unsigned char *) &lp->d_interleave);
conv2FromEcoToX86((unsigned char *) &lp->d_trackskew);
conv2FromEcoToX86((unsigned char *) &lp->d_cylskew);
conv4FromEcoToX86((unsigned char *) &lp->d_headswitch);
conv4FromEcoToX86((unsigned char *) &lp->d_trkseek);
conv4FromEcoToX86((unsigned char *) &lp->d_flags);
for (i = 0; i < NDDATA; i++) {
conv4FromEcoToX86((unsigned char *) &lp->d_drivedata[i]);
}
for (i = 0; i < NSPARE; i++) {
conv4FromEcoToX86((unsigned char *) &lp->d_spare[i]);
}
conv4FromEcoToX86((unsigned char *) &lp->d_magic2);
conv2FromEcoToX86((unsigned char *) &lp->d_checksum);
conv2FromEcoToX86((unsigned char *) &lp->d_npartitions);
numParts = lp->d_npartitions;
if (numParts < 0 || numParts > MAXPARTS) {
printf("Warning: number of partitions out of range!\n");
numParts = MAXPARTS;
}
conv4FromEcoToX86((unsigned char *) &lp->d_bbsize);
conv4FromEcoToX86((unsigned char *) &lp->d_sbsize);
for (i = 0; i < MAXPARTS; i++) {
conv4FromEcoToX86((unsigned char *) &lp->d_parts[i].p_size);
conv4FromEcoToX86((unsigned char *) &lp->d_parts[i].p_offset);
conv4FromEcoToX86((unsigned char *) &lp->d_parts[i].p_fsize);
conv2FromEcoToX86((unsigned char *) &lp->d_parts[i].p_cpg);
}
/* after byte-swapping, the checksum must be calculated again */
lp->d_checksum = 0;
lp->d_checksum = chksum(lp, numParts);
/* Attention: the new checksum must not be converted! */
}
 
 
void dlFromX86ToEco(DiskLabel *lp) {
int i;
int numParts;
 
conv4FromX86ToEco((unsigned char *) &lp->d_magic);
conv2FromX86ToEco((unsigned char *) &lp->d_type);
conv2FromX86ToEco((unsigned char *) &lp->d_subtype);
conv4FromX86ToEco((unsigned char *) &lp->d_secsize);
conv4FromX86ToEco((unsigned char *) &lp->d_nsectors);
conv4FromX86ToEco((unsigned char *) &lp->d_ntracks);
conv4FromX86ToEco((unsigned char *) &lp->d_ncylinders);
conv4FromX86ToEco((unsigned char *) &lp->d_secpercyl);
conv4FromX86ToEco((unsigned char *) &lp->d_secperunit);
conv2FromX86ToEco((unsigned char *) &lp->d_sparespertrack);
conv2FromX86ToEco((unsigned char *) &lp->d_sparespercyl);
conv4FromX86ToEco((unsigned char *) &lp->d_acylinders);
conv2FromX86ToEco((unsigned char *) &lp->d_rpm);
conv2FromX86ToEco((unsigned char *) &lp->d_interleave);
conv2FromX86ToEco((unsigned char *) &lp->d_trackskew);
conv2FromX86ToEco((unsigned char *) &lp->d_cylskew);
conv4FromX86ToEco((unsigned char *) &lp->d_headswitch);
conv4FromX86ToEco((unsigned char *) &lp->d_trkseek);
conv4FromX86ToEco((unsigned char *) &lp->d_flags);
for (i = 0; i < NDDATA; i++) {
conv4FromX86ToEco((unsigned char *) &lp->d_drivedata[i]);
}
for (i = 0; i < NSPARE; i++) {
conv4FromX86ToEco((unsigned char *) &lp->d_spare[i]);
}
conv4FromX86ToEco((unsigned char *) &lp->d_magic2);
conv2FromX86ToEco((unsigned char *) &lp->d_checksum);
numParts = lp->d_npartitions;
if (numParts < 0 || numParts > MAXPARTS) {
printf("Warning: number of partitions out of range!\n");
numParts = MAXPARTS;
}
conv2FromX86ToEco((unsigned char *) &lp->d_npartitions);
conv4FromX86ToEco((unsigned char *) &lp->d_bbsize);
conv4FromX86ToEco((unsigned char *) &lp->d_sbsize);
for (i = 0; i < MAXPARTS; i++) {
conv4FromX86ToEco((unsigned char *) &lp->d_parts[i].p_size);
conv4FromX86ToEco((unsigned char *) &lp->d_parts[i].p_offset);
conv4FromX86ToEco((unsigned char *) &lp->d_parts[i].p_fsize);
conv2FromX86ToEco((unsigned char *) &lp->d_parts[i].p_cpg);
}
/* after byte-swapping, the checksum must be calculated again */
lp->d_checksum = 0;
lp->d_checksum = chksum(lp, numParts);
/* Attention: the new checksum must not be converted! */
}
 
 
/**************************************************************/
 
 
FILE *diskFile;
unsigned long sliceStart;
unsigned long sliceSize;
 
 
void readSector(unsigned int sno, unsigned char *buf) {
int n;
 
if (sno >= sliceSize) {
error("illegal sector number %u in readSector()", sno);
}
fseek(diskFile, (sliceStart + sno) * SSIZE, SEEK_SET);
n = fread(buf, 1, SSIZE, diskFile);
if (n != SSIZE) {
error("read error on sector %u", sno);
}
}
 
 
void writeSector(unsigned int sno, unsigned char *buf) {
int n;
 
if (sno >= sliceSize) {
error("illegal sector number %u in writeSector()", sno);
}
fseek(diskFile, (sliceStart + sno) * SSIZE, SEEK_SET);
n = fwrite(buf, 1, SSIZE, diskFile);
if (n != SSIZE) {
error("write error on sector %u", sno);
}
}
 
 
/**************************************************************/
 
 
void showDiskLabel(DiskLabel *lp) {
int i;
int c;
int numParts;
 
printf("magic number : 0x%08X\n", lp->d_magic);
if (lp->d_magic != DSKMAGIC) {
printf("Warning: wrong magic number!\n");
}
printf("type : 0x%04X\n", lp->d_type);
printf("subtype : 0x%04X\n", lp->d_subtype);
printf("typename : '");
for (i = 0; i < NTYPENAME; i++) {
c = lp->d_typename[i];
if (c == 0) {
break;
}
if (c >= 0x20 && c < 0x7F) {
printf("%c", c);
} else {
printf(".");
}
}
printf("'\n");
printf("packname : '");
for (i = 0; i < NPACKNAME; i++) {
c = lp->d_packname[i];
if (c == 0) {
break;
}
if (c >= 0x20 && c < 0x7F) {
printf("%c", c);
} else {
printf(".");
}
}
printf("'\n");
printf("secsize : 0x%08X\n", lp->d_secsize);
printf("nsectors : 0x%08X\n", lp->d_nsectors);
printf("ntracks : 0x%08X\n", lp->d_ntracks);
printf("ncylinders : 0x%08X\n", lp->d_ncylinders);
printf("secpercyl : 0x%08X\n", lp->d_secpercyl);
printf("secperunit : 0x%08X\n", lp->d_secperunit);
printf("sparespertrack : 0x%04X\n", lp->d_sparespertrack);
printf("sparespercyl : 0x%04X\n", lp->d_sparespercyl);
printf("acylinders : 0x%08X\n", lp->d_acylinders);
printf("rpm : 0x%04X\n", lp->d_rpm);
printf("interleave : 0x%04X\n", lp->d_interleave);
printf("trackskew : 0x%04X\n", lp->d_trackskew);
printf("cylskew : 0x%04X\n", lp->d_cylskew);
printf("headswitch : 0x%08X\n", lp->d_headswitch);
printf("trkseek : 0x%08X\n", lp->d_trkseek);
printf("flags : 0x%08X\n", lp->d_flags);
printf("magic2 : 0x%08X\n", lp->d_magic2);
if (lp->d_magic2 != DSKMAGIC) {
printf("Warning: wrong magic number!\n");
}
printf("checksum : 0x%04X\n", lp->d_checksum);
printf("bbsize : 0x%08X\n", lp->d_bbsize);
printf("sbsize : 0x%08X\n", lp->d_sbsize);
printf("npartitions : 0x%04X\n", lp->d_npartitions);
numParts = lp->d_npartitions;
if (numParts < 0 || numParts > MAXPARTS) {
printf("Warning: number of partitions out of range!\n");
numParts = MAXPARTS;
}
for (i = 0; i < numParts; i++) {
if (lp->d_parts[i].p_size == 0) {
continue;
}
printf(" partition %c:\n", 'a' + i);
printf(" size : 0x%08X\n", lp->d_parts[i].p_size);
printf(" offset : 0x%08X\n", lp->d_parts[i].p_offset);
printf(" fsize : 0x%08X\n", lp->d_parts[i].p_fsize);
printf(" fstype : 0x%02X\n", lp->d_parts[i].p_fstype);
printf(" frag : 0x%02X\n", lp->d_parts[i].p_frag);
printf(" cpg : 0x%04X\n", lp->d_parts[i].p_cpg);
}
}
 
 
/**************************************************************/
 
 
void initDiskLabel(DiskLabel *lp) {
int i;
 
lp->d_magic = 0;
lp->d_type = 0;
lp->d_subtype = 0;
for (i = 0; i < NTYPENAME; i++) {
lp->d_typename[i] = 0;
}
for (i = 0; i < NPACKNAME; i++) {
lp->d_packname[i] = 0;
}
lp->d_secsize = 0;
lp->d_nsectors = 0;
lp->d_ntracks = 0;
lp->d_ncylinders = 0;
lp->d_secpercyl = 0;
lp->d_secperunit = 0;
lp->d_sparespertrack = 0;
lp->d_sparespercyl = 0;
lp->d_acylinders = 0;
lp->d_rpm = 0;
lp->d_interleave = 0;
lp->d_trackskew = 0;
lp->d_cylskew = 0;
lp->d_headswitch = 0;
lp->d_trkseek = 0;
lp->d_flags = 0;
for (i = 0; i < NDDATA; i++) {
lp->d_drivedata[i] = 0;
}
for (i = 0; i < NSPARE; i++) {
lp->d_spare[i] = 0;
}
lp->d_magic2 = 0;
lp->d_checksum = 0;
lp->d_npartitions = 0;
lp->d_bbsize = 0;
lp->d_sbsize = 0;
for (i = 0; i < MAXPARTS; i++) {
lp->d_parts[i].p_size = 0;
lp->d_parts[i].p_offset = 0;
lp->d_parts[i].p_fsize = 0;
lp->d_parts[i].p_fstype = 0;
lp->d_parts[i].p_frag = 0;
lp->d_parts[i].p_cpg = 0;
}
for (i = 0; i < PADSIZE; i++) {
lp->d_pad[i] = 0;
}
}
 
 
void fillDiskLabelDefault1(DiskLabel *lp) {
/* the default disklabel for a non-partitioned disk */
lp->d_magic = DSKMAGIC;
strcpy(lp->d_typename, "ECO32 SD-100M");
lp->d_secsize = 512;
lp->d_nsectors = 128;
lp->d_ntracks = 16;
lp->d_ncylinders = 100;
lp->d_secpercyl = 2048;
lp->d_secperunit = 204800;
lp->d_sparespertrack = 0;
lp->d_sparespercyl = 0;
lp->d_acylinders = 0;
lp->d_rpm = 3600;
lp->d_interleave = 1;
lp->d_trackskew = 0;
lp->d_cylskew = 0;
lp->d_headswitch = 0;
lp->d_trkseek = 0;
lp->d_flags = 0;
lp->d_magic2 = DSKMAGIC;
lp->d_checksum = 0;
lp->d_npartitions = 16;
lp->d_bbsize = 8192;
lp->d_sbsize = 8192;
/*-------------------------------*/
lp->d_parts[0].p_size = 172032;
lp->d_parts[0].p_offset = 0;
lp->d_parts[0].p_fsize = 1024;
lp->d_parts[0].p_fstype = 7;
lp->d_parts[0].p_frag = 8;
/*-------------------------------*/
lp->d_parts[1].p_size = 32768;
lp->d_parts[1].p_offset = 172032;
lp->d_parts[1].p_fsize = 0;
lp->d_parts[1].p_fstype = 1;
lp->d_parts[1].p_frag = 0;
/*-------------------------------*/
lp->d_parts[2].p_size = 204800;
lp->d_parts[2].p_offset = 0;
lp->d_parts[2].p_fsize = 0;
lp->d_parts[2].p_fstype = 0;
lp->d_parts[2].p_frag = 0;
/*-------------------------------*/
lp->d_checksum = chksum(lp, lp->d_npartitions);
}
 
 
void fillDiskLabelDefault2(DiskLabel *lp) {
/* the default disklabel for a partitioned disk */
lp->d_magic = DSKMAGIC;
strcpy(lp->d_typename, "ECO32 SD-100M");
lp->d_secsize = 512;
lp->d_nsectors = 128;
lp->d_ntracks = 16;
lp->d_ncylinders = 100;
lp->d_secpercyl = 2048;
lp->d_secperunit = 204800;
lp->d_sparespertrack = 0;
lp->d_sparespercyl = 0;
lp->d_acylinders = 0;
lp->d_rpm = 3600;
lp->d_interleave = 1;
lp->d_trackskew = 0;
lp->d_cylskew = 0;
lp->d_headswitch = 0;
lp->d_trkseek = 0;
lp->d_flags = 0;
lp->d_magic2 = DSKMAGIC;
lp->d_checksum = 0;
lp->d_npartitions = 16;
lp->d_bbsize = 8192;
lp->d_sbsize = 8192;
/*-------------------------------*/
lp->d_parts[0].p_size = 106496;
lp->d_parts[0].p_offset = 81920;
lp->d_parts[0].p_fsize = 1024;
lp->d_parts[0].p_fstype = 7;
lp->d_parts[0].p_frag = 8;
/*-------------------------------*/
lp->d_parts[1].p_size = 16384;
lp->d_parts[1].p_offset = 188416;
lp->d_parts[1].p_fsize = 0;
lp->d_parts[1].p_fstype = 1;
lp->d_parts[1].p_frag = 0;
/*-------------------------------*/
lp->d_parts[2].p_size = 122880;
lp->d_parts[2].p_offset = 81920;
lp->d_parts[2].p_fsize = 0;
lp->d_parts[2].p_fstype = 0;
lp->d_parts[2].p_frag = 0;
/*-------------------------------*/
lp->d_parts[3].p_size = 204800;
lp->d_parts[3].p_offset = 0;
lp->d_parts[3].p_fsize = 0;
lp->d_parts[3].p_fstype = 0;
lp->d_parts[3].p_frag = 0;
/*-------------------------------*/
lp->d_checksum = chksum(lp, lp->d_npartitions);
}
 
 
void fillDiskLabelFromFile(DiskLabel *lp, char *fileName) {
error("configuration file not supported yet");
}
 
 
/**************************************************************/
 
 
int checkEndian(DiskLabel *lp) {
int endian;
uint32_t magic;
uint16_t numParts;
uint16_t sum;
 
magic = lp->d_magic;
if (magic != lp->d_magic2) {
printf("Warning: magic numbers differ!\n");
return -1;
}
if (magic == DSKMAGIC) {
/* little endian */
endian = 1;
} else {
/* assume big endian */
endian = 0;
/* and check */
conv4FromEcoToX86((unsigned char *) &magic);
if (magic != DSKMAGIC) {
/* neither little endian nor big endian */
printf("Warning: wrong magic number!\n");
return -2;
}
}
numParts = lp->d_npartitions;
if (endian == 0) {
conv2FromEcoToX86((unsigned char *) &numParts);
}
sum = chksum(lp, (int) numParts);
if (sum != 0) {
printf("Warning: wrong checksum!\n");
return -3;
}
return endian;
}
 
 
/**************************************************************/
 
 
void usage(char *myself) {
printf("Usage:\n");
printf(" %s -c <disk> <partition or '*'>\n", myself);
printf(" %s -t <disk> <partition or '*'>\n", myself);
printf(" %s -rb <disk> <partition or '*'>\n", myself);
printf(" %s -rl <disk> <partition or '*'>\n", myself);
printf(" %s -wb <disk> <partition or '*'> [<config file>]\n", myself);
printf(" %s -wl <disk> <partition or '*'> [<config file>]\n", myself);
printf("c: check, t: toggle endianness\n");
printf("r: read, w: write disklabel\n");
printf("b: big, l: little endian\n");
}
 
 
int main(int argc, char *argv[]) {
int optionCheck;
int optionToggle;
int optionRead;
int optionBig;
char *diskName;
int part;
char *endptr;
unsigned char partTable[SSIZE];
unsigned char *ptptr;
unsigned long partType;
DiskLabel dl;
int endian;
 
if (argc != 4 && argc != 5) {
usage(argv[0]);
exit(1);
}
if (strcmp(argv[1], "-c") != 0 &&
strcmp(argv[1], "-t") != 0 &&
strcmp(argv[1], "-rb") != 0 &&
strcmp(argv[1], "-rl") != 0 &&
strcmp(argv[1], "-wb") != 0 &&
strcmp(argv[1], "-wl") != 0) {
usage(argv[0]);
exit(1);
}
if (strcmp(argv[1], "-c") == 0) {
optionCheck = 1;
optionToggle = 0;
optionRead = 0;
optionBig = 0;
} else
if (strcmp(argv[1], "-t") == 0) {
optionCheck = 1;
optionToggle = 1;
optionRead = 0;
optionBig = 0;
} else {
optionCheck = 0;
optionToggle = 0;
optionRead = (argv[1][1] == 'r');
optionBig = (argv[1][2] == 'b');
}
diskName = argv[2];
diskFile = fopen(diskName, "r+b");
if (diskFile == NULL) {
error("cannot open disk image '%s'", diskName);
}
if (strcmp(argv[3], "*") == 0) {
/* whole disk contains one single slice */
sliceStart = 0;
fseek(diskFile, 0, SEEK_END);
sliceSize = ftell(diskFile) / SSIZE;
} else {
/* argv[3] is partition number of NetBSD slice */
part = strtoul(argv[3], &endptr, 10);
if (*endptr != '\0' || part < 0 || part > 15) {
error("illegal partition number '%s'", argv[3]);
}
fseek(diskFile, 1 * SSIZE, SEEK_SET);
if (fread(partTable, 1, SSIZE, diskFile) != SSIZE) {
error("cannot read partition table of disk '%s'", diskName);
}
ptptr = partTable + part * 32;
partType = read4FromEco(ptptr + 0);
if ((partType & 0x7FFFFFFF) != 0x000000A9) {
error("partition %d of disk '%s' is not a NetBSD slice",
part, diskName);
}
sliceStart = read4FromEco(ptptr + 4);
sliceSize = read4FromEco(ptptr + 8);
}
printf("Slice size is %lu (0x%lX) sectors of %d bytes each.\n",
sliceSize, sliceSize, SSIZE);
if (optionCheck) {
/* check endianness */
readSector(1, (unsigned char *) &dl);
endian = checkEndian(&dl);
if (endian < 0) {
error("the endiannes of the disklabel could not be determined");
}
printf("The disklabel appears to be %s-endian.\n",
endian == 0 ? "big" : "little");
if (optionToggle) {
/* toggle endianness */
if (endian == 0) {
/* big -> little */
dlFromEcoToX86(&dl);
} else {
/* little -> big */
dlFromX86ToEco(&dl);
}
endian = checkEndian(&dl);
if (endian < 0) {
error("this should never happen");
}
printf("The disklabel has been converted to %s-endian.\n",
endian == 0 ? "big" : "little");
writeSector(1, (unsigned char *) &dl);
}
} else
if (optionRead) {
/* read and show disklabel */
readSector(1, (unsigned char *) &dl);
if (optionBig) {
dlFromEcoToX86(&dl);
}
showDiskLabel(&dl);
} else {
/* write disklabel */
initDiskLabel(&dl);
if (argc == 4) {
fillDiskLabelDefault2(&dl);
} else {
fillDiskLabelFromFile(&dl, argv[4]);
}
if (optionBig) {
dlFromX86ToEco(&dl);
}
writeSector(1, (unsigned char *) &dl);
}
fclose(diskFile);
return 0;
}
/disk/tools/fs-NetBSD/dsklbl/Makefile
0,0 → 1,36
#
# Makefile for dsklbl utility
#
 
BUILD = ../../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = dsklbl.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = NetBSD-dsklbl
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/tools/fs-NetBSD/mkboot/stage1/br.s
0,0 → 1,128
;
; br.s -- the boot record
;
 
; Runtime environment:
;
; This code must be loaded and started at 0xC0000000.
; It allocates a stack from 0xC0001000 downwards. So
; it must run within 4K (code + data + stack).
;
; This code expects the disk number of the boot disk
; in $16, the start sector of the disk or partition
; to be booted in $17 and its size in $18.
;
; The boot loader, which is loaded by this code,
; must be in standalone (headerless) executable
; format, stored at partition relative disk
; sectors 2..15 (i.e., the boot block), and
; gets loaded and started at 0xC0001000.
 
.set stacktop,0xC0001000 ; top of stack
.set loadaddr,0xC0001000 ; where to load the boot loader
 
.set cout,0xE0000018 ; ROM console output
.set dskio,0xE0000030 ; ROM disk I/O
 
; reset arrives here
reset:
j start
 
; interrupts arrive here
intrpt:
j userMiss
 
; user TLB misses arrive here
userMiss:
add $4,$0,intmsg ; we do not expect any interrupt
jal msgout
j halt
 
; load the boot loader and start it
start:
add $29,$0,stacktop ; setup stack
add $4,$0,strtmsg ; say what is going on
jal msgout
add $4,$0,2 ; start loading with sector 2
add $5,$0,loadaddr ; where to load the boot loader
and $5,$5,0x3FFFFFFF ; convert to physical address
add $6,$0,14 ; 14 sectors to load
jal rdsct
add $8,$0,loadaddr ; start executing the boot loader
jr $8
 
; read disk sectors
; $4 start sector number (disk or partition relative)
; $5 transfer address
; $6 number of sectors
rdsct:
sub $29,$29,32
stw $31,$29,20
stw $6,$29,16 ; sector count
add $7,$5,$0 ; transfer address
add $6,$4,$17 ; relative sector -> absolute
add $5,$0,'r' ; command
add $4,$0,$16 ; disk number
add $8,$0,dskio
jalr $8
bne $2,$0,rderr ; error?
ldw $31,$29,20
add $29,$29,32
jr $31
 
; disk read error
rderr:
add $4,$0,dremsg
jal msgout
j halt
 
; output message
; $4 pointer to string
msgout:
sub $29,$29,8
stw $31,$29,4
stw $16,$29,0
add $16,$4,0 ; $16: pointer to string
msgout1:
ldbu $4,$16,0 ; get character
beq $4,$0,msgout2 ; done?
jal chrout ; output character
add $16,$16,1 ; bump pointer
j msgout1 ; continue
msgout2:
ldw $16,$29,0
ldw $31,$29,4
add $29,$29,8
jr $31
 
; output character
; $4 character
chrout:
sub $29,$29,4
stw $31,$29,0
add $8,$0,cout
jalr $8
ldw $31,$29,0
add $29,$29,4
jr $31
 
; halt execution by looping
halt:
add $4,$0,hltmsg
jal msgout
halt1:
j halt1
 
; messages
intmsg:
.byte "unexpected interrupt", 0x0D, 0x0A, 0
strtmsg:
.byte "BR executing...", 0x0D, 0x0A, 0
dremsg:
.byte "disk read error", 0x0D, 0x0A, 0
hltmsg:
.byte "bootstrap halted", 0x0D, 0x0A, 0
 
; boot record signature
.locate 512-2
.byte 0x55, 0xAA
/disk/tools/fs-NetBSD/mkboot/stage1/Makefile
0,0 → 1,16
#
# Makefile to build the boot record
#
 
BUILD = ../../../../../build
 
all: br.bin
 
br.bin: br.o
$(BUILD)/bin/ld -h -rc 0xC0000000 -o br.bin br.o
 
br.o: br.s
$(BUILD)/bin/as -o br.o br.s
 
clean:
rm -f *~ br.o br.bin
/disk/tools/fs-NetBSD/mkboot/stage2/disklabel.h
0,0 → 1,62
/*
* disklabel.h -- structure of the disklabel
*/
 
 
#ifndef _DISKLABEL_H_
#define _DISKLABEL_H_
 
 
#define DSKMAGIC 0x82564557
#define NTYPENAME 16
#define NPACKNAME 16
#define NDDATA 5
#define NSPARE 5
#define MAXPARTS 16
#define PADSIZE 108
 
 
typedef struct {
uint32_t p_size; /* number of sectors in partition */
uint32_t p_offset; /* starting sector */
uint32_t p_fsize; /* filesystem basic fragment size */
uint8_t p_fstype; /* filesystem type */
uint8_t p_frag; /* filesystem fragments per block */
uint16_t p_cpg; /* filesystem cylinders per group */
} Partition;
 
typedef struct {
uint32_t d_magic; /* magic number */
uint16_t d_type; /* drive type */
uint16_t d_subtype; /* controller, d_type specific */
char d_typename[NTYPENAME]; /* type name */
char d_packname[NPACKNAME]; /* pack identifier */
uint32_t d_secsize; /* bytes per sector */
uint32_t d_nsectors; /* data sectors per track */
uint32_t d_ntracks; /* tracks per cylinder */
uint32_t d_ncylinders; /* data cylinders per unit */
uint32_t d_secpercyl; /* data sectors per cylinder */
uint32_t d_secperunit; /* data sectors per unit */
uint16_t d_sparespertrack; /* spare sectors per track */
uint16_t d_sparespercyl; /* spare sectors per cylinder */
uint32_t d_acylinders; /* alternative cylinders per unit */
uint16_t d_rpm; /* rotational speed */
uint16_t d_interleave; /* hardware sector interleave */
uint16_t d_trackskew; /* sector 0 skew, per track */
uint16_t d_cylskew; /* sector 0 skew, per cylinder */
uint32_t d_headswitch; /* head switch time, usec */
uint32_t d_trkseek; /* track-to-track seek, usec */
uint32_t d_flags; /* generic flags */
uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
uint32_t d_spare[NSPARE]; /* reserved for future use */
uint32_t d_magic2; /* the magic number again */
uint16_t d_checksum; /* xor of data incl partitions */
uint16_t d_npartitions; /* number of partitions */
uint32_t d_bbsize; /* size of boot area at sector 0, bytes */
uint32_t d_sbsize; /* size of filesystem superblock, bytes */
Partition d_parts[MAXPARTS]; /* the partition table */
uint8_t d_pad[PADSIZE]; /* pad up to sector size */
} DiskLabel;
 
 
#endif /* _DISKLABEL_H_ */
/disk/tools/fs-NetBSD/mkboot/stage2/biolib.s
0,0 → 1,26
;
; biolib.s -- basic I/O library
;
 
.set cin,0xE0000010
.set cout,0xE0000018
.set dskio,0xE0000030
 
.export getc
.export putc
.export rwscts
 
.code
.align 4
 
getc:
add $8,$0,cin
jr $8
 
putc:
add $8,$0,cout
jr $8
 
rwscts:
add $8,$0,dskio
jr $8
/disk/tools/fs-NetBSD/mkboot/stage2/c0.s
0,0 → 1,59
;
; c0.s -- startup code and begin-of-segment labels
;
 
.import main
 
.import _ecode
.import _edata
.import _ebss
 
.export _bcode
.export _bdata
.export _bbss
 
.import bootDisk
.import startSector
.import numSectors
.import entryPoint
 
.code
_bcode:
 
start:
add $10,$0,_bdata ; copy data segment
add $8,$0,_edata
sub $9,$8,$10
add $9,$9,_ecode
j cpytest
cpyloop:
ldw $11,$9,0
stw $11,$8,0
cpytest:
sub $8,$8,4
sub $9,$9,4
bgeu $8,$10,cpyloop
add $8,$0,_bbss ; clear bss segment
add $9,$0,_ebss
j clrtest
clrloop:
stw $0,$8,0
add $8,$8,4
clrtest:
bltu $8,$9,clrloop
add $29,$0,0xC0010000 ; setup stack
stw $16,$0,bootDisk ; make arguments available
stw $17,$0,startSector
stw $18,$0,numSectors
jal main ; call 'main' function
ldw $16,$0,bootDisk ; setup arguments for next stage
ldw $17,$0,startSector
ldw $18,$0,numSectors
ldw $31,$0,entryPoint ; jump to loaded program
jr $31
 
.data
_bdata:
 
.bss
_bbss:
/disk/tools/fs-NetBSD/mkboot/stage2/boot.c
0,0 → 1,631
/*
* boot.c -- the bootstrap (boot loader)
*/
 
 
#include "types.h"
#include "disklabel.h"
#include "fs.h"
#include "dinode.h"
#include "dir.h"
#include "stdarg.h"
#include "biolib.h"
 
 
/**************************************************************/
 
/* constants and data types */
 
 
#define LOADER_NAME "loader" /* name of loader in root dir */
#define LOADER_ADDR 0xC0300000 /* where to load the loader */
 
#define SSHIFT 9 /* ld of sector size */
#define SSIZE (1 << SSHIFT) /* disk sector size in bytes */
#define SMASK (SSIZE - 1) /* sector mask */
 
#define BSHIFT 13 /* ld of block size */
#define BSIZE (1 << BSHIFT) /* disk block size in bytes */
#define BMASK (BSIZE - 1) /* block mask */
 
 
typedef struct ufs1_dinode Dinode;
typedef struct direct Dirent;
typedef unsigned int daddr_t;
typedef unsigned int ino_t;
 
 
#define NIPB (BSIZE / sizeof(Dinode))
 
#define NULL 0
 
 
/**************************************************************/
 
/* debugging */
 
 
Bool debugReadSectors = FALSE;
Bool debugReadDiskLabel = FALSE;
Bool debugReadSuperBlock = FALSE;
Bool debugGetInode = FALSE;
Bool debugSearchDir = FALSE;
Bool debugLoadLoader = FALSE;
 
 
/**************************************************************/
 
/* string support */
 
 
int strlen(char *str) {
int i;
 
i = 0;
while (*str++ != '\0') {
i++;
}
return i;
}
 
 
int strcmp(char *str1, char *str2) {
while (*str1 == *str2) {
if (*str1 == '\0') {
return 0;
}
str1++;
str2++;
}
return (* (unsigned char *) str1) - (* (unsigned char *) str2);
}
 
 
/**************************************************************/
 
/* scaled-down version of printf */
 
 
/*
* Output a character on the console.
* Replace LF by CR/LF.
*/
void putchar(char c) {
if (c == '\n') {
putchar('\r');
}
putc(c);
}
 
 
/*
* Count the number of characters needed to represent
* a given number in base 10.
*/
int countPrintn(long n) {
long a;
int res;
 
res = 0;
if (n < 0) {
res++;
n = -n;
}
a = n / 10;
if (a != 0) {
res += countPrintn(a);
}
return res + 1;
}
 
 
/*
* Output a number in base 10.
*/
void printn(long n) {
long a;
 
if (n < 0) {
putchar('-');
n = -n;
}
a = n / 10;
if (a != 0) {
printn(a);
}
putchar(n % 10 + '0');
}
 
 
/*
* Count the number of characters needed to represent
* a given number in a given base.
*/
int countPrintu(unsigned long n, unsigned long b) {
unsigned long a;
int res;
 
res = 0;
a = n / b;
if (a != 0) {
res += countPrintu(a, b);
}
return res + 1;
}
 
 
/*
* Output a number in a given base.
*/
void printu(unsigned long n, unsigned long b, Bool upperCase) {
unsigned long a;
 
a = n / b;
if (a != 0) {
printu(a, b, upperCase);
}
if (upperCase) {
putchar("0123456789ABCDEF"[n % b]);
} else {
putchar("0123456789abcdef"[n % b]);
}
}
 
 
/*
* Output a number of filler characters.
*/
void fill(int numFillers, char filler) {
while (numFillers-- > 0) {
putchar(filler);
}
}
 
 
/*
* Formatted output with a variable argument list.
*/
void vprintf(char *fmt, va_list ap) {
char c;
int n;
long ln;
unsigned int u;
unsigned long lu;
char *s;
Bool negFlag;
char filler;
int width, count;
 
while (1) {
while ((c = *fmt++) != '%') {
if (c == '\0') {
return;
}
putchar(c);
}
c = *fmt++;
if (c == '-') {
negFlag = TRUE;
c = *fmt++;
} else {
negFlag = FALSE;
}
if (c == '0') {
filler = '0';
c = *fmt++;
} else {
filler = ' ';
}
width = 0;
while (c >= '0' && c <= '9') {
width *= 10;
width += c - '0';
c = *fmt++;
}
if (c == 'd') {
n = va_arg(ap, int);
count = countPrintn(n);
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printn(n);
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
u = va_arg(ap, int);
count = countPrintu(u,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printu(u,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
c == 'X');
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'l') {
c = *fmt++;
if (c == 'd') {
ln = va_arg(ap, long);
count = countPrintn(ln);
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printn(ln);
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
lu = va_arg(ap, long);
count = countPrintu(lu,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
printu(lu,
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
c == 'X');
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else {
putchar('l');
putchar(c);
}
} else
if (c == 's') {
s = va_arg(ap, char *);
count = strlen(s);
if (width > 0 && !negFlag) {
fill(width - count, filler);
}
while ((c = *s++) != '\0') {
putchar(c);
}
if (width > 0 && negFlag) {
fill(width - count, filler);
}
} else
if (c == 'c') {
c = va_arg(ap, char);
putchar(c);
} else {
putchar(c);
}
}
}
 
 
/*
* Formatted output.
* This is a scaled-down version of the C library's
* printf. Used to print diagnostic information on
* the console (and optionally to a logfile).
*/
void printf(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
 
 
/**************************************************************/
 
/* halt with error message */
 
 
void halt(char *msg) {
printf(msg);
printf(", machine halted.\n");
while (1) ;
}
 
 
/**************************************************************/
 
/* disk I/O */
 
 
unsigned int bootDisk = 0; /* gets loaded by previous stage */
/* never changed */
unsigned int startSector = 0; /* gets loaded by previous stage */
/* initially holds start of slice */
/* disklabel read --> start of partition */
unsigned int numSectors = 0; /* gets loaded by previous stage */
/* initially holds size of slice */
/* disklabel read --> size of partition */
 
unsigned int spf; /* superblock read --> sectors per fragment */
unsigned int spb; /* superblock read --> sectors per block */
 
 
/*
* read disk sectors
*
* NOTE: buffer must be word-aligned
*/
void readSectors(unsigned int start,
unsigned int count,
void *buffer) {
unsigned int sector;
int result;
 
if (start + count > numSectors) {
halt("Sector number exceeds slice or partition size");
}
sector = startSector + start;
if (debugReadSectors) {
printf("DEBUG: reading sector 0x%08X, %d sectors\n", sector, count);
}
result = rwscts(bootDisk, 'r', sector,
(unsigned int) buffer & 0x3FFFFFFF, count);
if (result != 0) {
halt("Load error");
}
}
 
 
/**************************************************************/
 
/* disklabel handling */
 
 
unsigned int diskLabel[SSIZE / sizeof(unsigned int)];
DiskLabel *dlp = (DiskLabel *) &diskLabel[0];
 
unsigned int superStart; /* partition-relative offset, in sectors */
unsigned int superSize; /* size, in sectors */
 
 
void readDiskLabel(void) {
readSectors(1, 1, dlp);
if (dlp->d_magic != DSKMAGIC ||
dlp->d_magic2 != DSKMAGIC) {
halt("Disklabel corrupted");
}
 
startSector = dlp->d_parts[0].p_offset;
numSectors = dlp->d_parts[0].p_size;
 
superStart = dlp->d_bbsize;
if ((superStart & SMASK) != 0) {
halt("Superblock offset is not multiple of sector size");
}
superStart >>= SSHIFT;
 
superSize = dlp->d_sbsize;
if ((superSize & SMASK) != 0) {
halt("Superblock size is not multiple of sector size");
}
if (superSize > BSIZE) {
halt("Superblock too big");
}
superSize >>= SSHIFT;
 
if (debugReadDiskLabel) {
printf("DEBUG: super start = %d sectors, super size = %d sectors\n",
superStart, superSize);
}
}
 
 
/**************************************************************/
 
/* superblock handling */
 
 
unsigned int superBlock[BSIZE / sizeof(unsigned int)];
struct fs *sbp = (struct fs *) &superBlock[0];
 
 
void readSuperBlock(void) {
readSectors(superStart, superSize, sbp);
if (sbp->fs_magic != FS_UFS1_MAGIC) {
halt("Wrong magic number in superblock");
}
spf = sbp->fs_fsize / SSIZE;
spb = sbp->fs_bsize / SSIZE;
if (sbp->fs_inopb != NIPB) {
halt("Wrong number of inodes per block");
}
if (debugReadSuperBlock) {
printf("DEBUG: %d sectors per fragment\n", spf);
printf("DEBUG: %d sectors per block\n", spb);
printf("DEBUG: %d inodes per block\n", NIPB);
}
}
 
 
/**************************************************************/
 
 
unsigned int sibno = 0;
unsigned int sib[8192 / sizeof(unsigned int)];
unsigned int *sibp = (unsigned int *) &sib[0];
 
 
/*
* read a block of a file
*
* NOTE: addr must be word-aligned
*/
void readFileBlock(Dinode *ip, int blkno, void *addr) {
unsigned int diskFrag;
 
if (blkno < NDADDR) {
/* direct block */
diskFrag = ip->di_db[blkno];
} else
if (blkno - NDADDR < sbp->fs_bsize / sizeof(int32_t)) {
/* single indirect block */
if (sibno != ip->di_ib[0]) {
sibno = ip->di_ib[0];
readSectors(sibno * spf, spb, sibp);
}
diskFrag = sibp[blkno - NDADDR];
} else {
/* double or triple indirect block */
halt("Cannot do double or triple indirect blocks");
}
readSectors(diskFrag * spf, spb, addr);
}
 
 
/**************************************************************/
 
/* inode handling */
 
 
unsigned int inodeBlock[BSIZE / sizeof(unsigned int)];
Dinode *ibp = (Dinode *) &inodeBlock[0];
 
 
Dinode *getInode(unsigned int inode) {
unsigned int fnum;
unsigned int inum;
Dinode *ip;
 
fnum = ino_to_fsba(sbp, inode);
inum = ino_to_fsbo(sbp, inode);
if (debugGetInode) {
printf("DEBUG: getting inode 0x%08X\n", inode);
printf("DEBUG: this is in fragment %d, inode %d\n", fnum, inum);
}
readSectors(fnum * spf, spb, ibp);
ip = ibp + inum;
if (ip->di_size[0] != 0) {
halt("File too big");
}
if (debugGetInode) {
printf("DEBUG: mode of file = 0x%04X\n", ip->di_mode);
printf("DEBUG: size of file = 0x%08X\n", ip->di_size[1]);
}
return ip;
}
 
 
/**************************************************************/
 
/* locate inode of loader in root dir */
 
 
unsigned int directoryBlock[BSIZE / sizeof(unsigned int)];
Dirent *dbp = (Dirent *) &directoryBlock[0];
 
 
Dinode *getLoader(char *loaderName) {
Dinode *ip;
unsigned int offset;
Dirent *dp;
unsigned int ino;
unsigned int len;
 
ip = getInode(ROOTINO);
if ((ip->di_mode & IFMT) != IFDIR) {
halt("No root directory");
}
offset = 0;
while (1) {
if (offset >= ip->di_size[1]) {
/* not found */
return NULL;
}
if ((offset & BMASK) == 0) {
/* read the next directory block */
readFileBlock(ip, offset >> BSHIFT, dbp);
dp = dbp;
}
ino = dp->d_fileno;
len = dp->d_reclen;
if (debugSearchDir) {
printf("DEBUG: ino = %4d, len = %4d, ", ino, len);
printf("dirsiz = %4d, name = %s\n", DIRSIZ(0, dp, 0), dp->d_name);
}
if (ino != 0) {
if (strcmp(loaderName, dp->d_name) == 0) {
/* found */
break;
}
}
/* no match, try next entry */
dp = (Dirent *) ((unsigned char *) dp + len);
offset += len;
}
/* get corresponding inode */
ip = getInode(ino);
if ((ip->di_mode & IFMT) != IFREG) {
printf("/%s ", loaderName);
halt(" is not a regular file");
}
return ip;
}
 
 
/**************************************************************/
 
/* load the loader */
 
 
void loadLoader(Dinode *ip) {
unsigned int numBlocks;
unsigned int nextBlock;
unsigned char *nextAddr;
 
numBlocks = (ip->di_size[1] + (BSIZE - 1)) / BSIZE;
nextBlock = 0;
nextAddr = (unsigned char *) LOADER_ADDR;
while (numBlocks--) {
if (debugLoadLoader) {
printf("DEBUG: loading block %d at 0x%08X\n", nextBlock, nextAddr);
}
readFileBlock(ip, nextBlock, nextAddr);
nextBlock++;
nextAddr += BSIZE;
}
}
 
 
/**************************************************************/
 
/* main program */
 
 
unsigned int entryPoint; /* where to continue from main() */
 
 
int main(void) {
Dinode *ip;
unsigned int saveBootDisk;
unsigned int saveStartSector;
unsigned int saveNumSectors;
 
/* save environment, see below */
saveBootDisk = bootDisk;
saveStartSector = startSector;
saveNumSectors = numSectors;
printf("Bootstrap loader executing...\n");
readDiskLabel();
readSuperBlock();
ip = getLoader(LOADER_NAME);
if (ip == NULL) {
printf("'/%s' ", LOADER_NAME);
halt("not found");
}
printf("Loading '/%s'...\n", LOADER_NAME);
loadLoader(ip);
printf("Starting '/%s'...\n", LOADER_NAME);
entryPoint = LOADER_ADDR;
/* restore environment: the loader expects exactly
the same entry conditions as the boot loader */
bootDisk = saveBootDisk;
startSector = saveStartSector;
numSectors = saveNumSectors;
return 0;
}
/disk/tools/fs-NetBSD/mkboot/stage2/c1.s
0,0 → 1,19
;
; c1.s -- end-of-segment labels
;
 
.export _ecode
.export _edata
.export _ebss
 
.code
.align 4
_ecode:
 
.data
.align 4
_edata:
 
.bss
.align 4
_ebss:
/disk/tools/fs-NetBSD/mkboot/stage2/dir.h
0,0 → 1,160
/* $NetBSD: dir.h,v 1.21 2009/07/22 04:49:19 dholland Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dir.h 8.5 (Berkeley) 4/27/95
*/
 
#ifndef _UFS_UFS_DIR_H_
#define _UFS_UFS_DIR_H_
 
/*
* Theoretically, directories can be more than 2Gb in length; however, in
* practice this seems unlikely. So, we define the type doff_t as a 32-bit
* quantity to keep down the cost of doing lookup on a 32-bit machine.
*/
#define doff_t int32_t
#define MAXDIRSIZE (0x7fffffff)
 
/*
* A directory consists of some number of blocks of DIRBLKSIZ
* bytes, where DIRBLKSIZ is chosen such that it can be transferred
* to disk in a single atomic operation (e.g. 512 bytes on most machines).
*
* Each DIRBLKSIZ byte block contains some number of directory entry
* structures, which are of variable length. Each directory entry has
* a struct direct at the front of it, containing its inode number,
* the length of the entry, and the length of the name contained in
* the entry. These are followed by the name padded to a 4 byte boundary.
* All names are guaranteed null terminated.
* The maximum length of a name in a directory is FFS_MAXNAMLEN.
*
* The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
* a directory entry. Free space in a directory is represented by
* entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZ bytes
* in a directory block are claimed by the directory entries. This
* usually results in the last entry in a directory having a large
* dp->d_reclen. When entries are deleted from a directory, the
* space is returned to the previous entry in the same directory
* block by increasing its dp->d_reclen. If the first entry of
* a directory block is free, then its dp->d_ino is set to 0.
* Entries other than the first in a directory do not normally have
* dp->d_ino set to 0.
*/
#undef DIRBLKSIZ
#define DIRBLKSIZ DEV_BSIZE
#define FFS_MAXNAMLEN 255
#define APPLEUFS_DIRBLKSIZ 1024
 
#define d_ino d_fileno
struct direct {
u_int32_t d_fileno; /* inode number of entry */
u_int16_t d_reclen; /* length of this record */
u_int8_t d_type; /* file type, see below */
u_int8_t d_namlen; /* length of string in d_name */
char d_name[FFS_MAXNAMLEN + 1];/* name with length <= FFS_MAXNAMLEN */
};
 
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
 
/*
* Convert between stat structure types and directory types.
*/
#define IFTODT(mode) (((mode) & 0170000) >> 12)
#define DTTOIF(dirtype) ((dirtype) << 12)
 
/*
* The DIRSIZ macro gives the minimum record length which will hold
* the directory entry. This requires the amount of space in struct direct
* without the d_name field, plus enough space for the name with a terminating
* null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
*/
#define DIRECTSIZ(namlen) \
((sizeof(struct direct) - (FFS_MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3))
 
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && !(needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#else
#define DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && (needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#endif
 
#define OLDDIRFMT 1
#define NEWDIRFMT 0
 
/*
* Template for manipulating directories. Should use struct direct's,
* but the name field is FFS_MAXNAMLEN - 1, and this just won't do.
*/
struct dirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int8_t dot_type;
u_int8_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int8_t dotdot_type;
u_int8_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
 
/*
* This is the old format of directories, sanz type element.
*/
struct odirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int16_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int16_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
#endif /* !_UFS_UFS_DIR_H_ */
/disk/tools/fs-NetBSD/mkboot/stage2/biolib.h
0,0 → 1,15
/*
* biolib.h -- basic I/O library
*/
 
 
#ifndef _BIOLIB_H_
#define _BIOLIB_H_
 
 
char getc(void);
void putc(char c);
int rwscts(int dskno, int cmd, int sector, int addr, int count);
 
 
#endif /* _BIOLIB_H_ */
/disk/tools/fs-NetBSD/mkboot/stage2/dinode.h
0,0 → 1,180
/* $NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp $ */
 
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dinode.h 8.9 (Berkeley) 3/29/95
*/
 
/*
* NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
*/
 
#ifndef _UFS_UFS_DINODE_H_
#define _UFS_UFS_DINODE_H_
 
/*
* The root inode is the root of the file system. Inode 0 can't be used for
* normal purposes and historically bad blocks were linked to inode 1, thus
* the root inode is 2. (Inode 1 is no longer used for this purpose, however
* numerous dump tapes make this assumption, so we are stuck with it).
*/
#define ROOTINO ((ino_t)2)
 
/*
* The Whiteout inode# is a dummy non-zero inode number which will
* never be allocated to a real file. It is used as a place holder
* in the directory entry which has been tagged as a DT_W entry.
* See the comments about ROOTINO above.
*/
#define WINO ((ino_t)1)
 
/*
* A dinode contains all the meta-data associated with a UFS file.
* This structure defines the on-disk format of a dinode. Since
* this structure describes an on-disk structure, all its fields
* are defined by types with precise widths.
*/
 
#define NXADDR 2
#define NDADDR 12 /* Direct addresses in inode. */
#define NIADDR 3 /* Indirect addresses in inode. */
 
struct ufs1_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
union {
u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */
u_int32_t inumber; /* 4: Lfs: inode number. */
} di_u;
u_int64_t di_size; /* 8: File byte count. */
int32_t di_atime; /* 16: Last access time. */
int32_t di_atimensec; /* 20: Last access time. */
int32_t di_mtime; /* 24: Last modified time. */
int32_t di_mtimensec; /* 28: Last modified time. */
int32_t di_ctime; /* 32: Last inode change time. */
int32_t di_ctimensec; /* 36: Last inode change time. */
int32_t di_db[NDADDR]; /* 40: Direct disk blocks. */
int32_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
u_int32_t di_flags; /* 100: Status flags (chflags). */
u_int32_t di_blocks; /* 104: Blocks actually held. */
int32_t di_gen; /* 108: Generation number. */
u_int32_t di_uid; /* 112: File owner. */
u_int32_t di_gid; /* 116: File group. */
u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */
};
 
struct ufs2_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
u_int32_t di_uid; /* 4: File owner. */
u_int32_t di_gid; /* 8: File group. */
u_int32_t di_blksize; /* 12: Inode blocksize. */
u_int64_t di_size; /* 16: File byte count. */
u_int64_t di_blocks; /* 24: Bytes actually held. */
int64_t di_atime; /* 32: Last access time. */
int64_t di_mtime; /* 40: Last modified time. */
int64_t di_ctime; /* 48: Last inode change time. */
int64_t di_birthtime; /* 56: Inode creation time. */
int32_t di_mtimensec; /* 64: Last modified time. */
int32_t di_atimensec; /* 68: Last access time. */
int32_t di_ctimensec; /* 72: Last inode change time. */
int32_t di_birthnsec; /* 76: Inode creation time. */
int32_t di_gen; /* 80: Generation number. */
u_int32_t di_kernflags; /* 84: Kernel flags. */
u_int32_t di_flags; /* 88: Status flags (chflags). */
int32_t di_extsize; /* 92: External attributes block. */
int64_t di_extb[NXADDR];/* 96: External attributes block. */
int64_t di_db[NDADDR]; /* 112: Direct disk blocks. */
int64_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */
int64_t di_spare[2]; /* 240: Reserved; currently unused */
};
 
/*
* The di_db fields may be overlaid with other information for
* file types that do not have associated disk storage. Block
* and character devices overlay the first data block with their
* dev_t value. Short symbolic links place their path in the
* di_db area.
*/
#define di_inumber di_u.inumber
#define di_ogid di_u.oldids[1]
#define di_ouid di_u.oldids[0]
#define di_rdev di_db[0]
#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(int32_t))
#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(int64_t))
 
#define MAXSYMLINKLEN(ip) \
((ip)->i_ump->um_fstype == UFS1) ? \
MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2
 
/* NeXT used to keep short symlinks in the inode even when using
* FS_42INODEFMT. In that case fs->fs_maxsymlinklen is probably -1,
* but short symlinks were stored in inodes shorter than this:
*/
#define APPLEUFS_MAXSYMLINKLEN 60
 
/* File permissions. */
#define IEXEC 0000100 /* Executable. */
#define IWRITE 0000200 /* Writable. */
#define IREAD 0000400 /* Readable. */
#define ISVTX 0001000 /* Sticky bit. */
#define ISGID 0002000 /* Set-gid. */
#define ISUID 0004000 /* Set-uid. */
 
/* File types. */
#define IFMT 0170000 /* Mask of file type. */
#define IFIFO 0010000 /* Named pipe (fifo). */
#define IFCHR 0020000 /* Character device. */
#define IFDIR 0040000 /* Directory file. */
#define IFBLK 0060000 /* Block device. */
#define IFREG 0100000 /* Regular file. */
#define IFLNK 0120000 /* Symbolic link. */
#define IFSOCK 0140000 /* UNIX domain socket. */
#define IFWHT 0160000 /* Whiteout. */
 
/* Size of the on-disk inode. */
#define DINODE1_SIZE (sizeof(struct ufs1_dinode)) /* 128 */
#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
 
#endif /* !_UFS_UFS_DINODE_H_ */
/disk/tools/fs-NetBSD/mkboot/stage2/types.h
0,0 → 1,38
/*
* types.h -- additional types
*/
 
 
#ifndef _TYPES_H_
#define _TYPES_H_
 
 
typedef unsigned int uint64_t[2];
typedef unsigned int u_int64_t[2];
 
typedef unsigned int uint32_t;
typedef unsigned int u_int32_t;
 
typedef unsigned short uint16_t;
typedef unsigned short u_int16_t;
 
typedef unsigned char uint8_t;
typedef unsigned char u_int8_t;
typedef unsigned char u_char;
 
typedef unsigned int int64_t[2];
 
typedef int int32_t;
 
typedef short int16_t;
 
typedef char int8_t;
 
 
typedef int Bool;
 
#define FALSE 0
#define TRUE 1
 
 
#endif /* _TYPES_H_ */
/disk/tools/fs-NetBSD/mkboot/stage2/stdarg.h
0,0 → 1,41
/*
* stdarg.h -- variable argument lists
*/
 
 
#ifndef _STDARG_H_
#define _STDARG_H_
 
 
typedef char *va_list;
 
 
static float __va_arg_tmp;
 
 
#define va_start(list, start) \
((void)((list) = (sizeof(start)<4 ? \
(char *)((int *)&(start)+1) : (char *)(&(start)+1))))
 
#define __va_arg(list, mode, n) \
(__typecode(mode)==1 && sizeof(mode)==4 ? \
(__va_arg_tmp = *(double *)(&(list += \
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \
*(mode *)&__va_arg_tmp) : \
*(mode *)(&(list += \
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)]))
 
#define _bigendian_va_arg(list, mode, n) \
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \
__va_arg(list, mode, n))
 
#define va_end(list) ((void)0)
 
#define va_arg(list, mode) \
(sizeof(mode)==8 ? \
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \
_bigendian_va_arg(list, mode, 3U))
 
 
#endif /* _STDARG_H_ */
/disk/tools/fs-NetBSD/mkboot/stage2/Makefile
0,0 → 1,26
#
# Makefile to build the bootstrap (boot loader)
#
 
BUILD = ../../../../../build
 
all: boot.bin
 
boot.bin: c0.o boot.o biolib.o c1.o
$(BUILD)/bin/ld -h -rc 0xC0001000 -o boot.bin \
c0.o boot.o biolib.o c1.o
 
c0.o: c0.s
$(BUILD)/bin/as -o c0.o c0.s
 
boot.o: boot.c
$(BUILD)/bin/lcc -A -c -o boot.o boot.c
 
biolib.o: biolib.s
$(BUILD)/bin/as -o biolib.o biolib.s
 
c1.o: c1.s
$(BUILD)/bin/as -o c1.o c1.s
 
clean:
rm -f *~ c0.o boot.o biolib.o c1.o boot.bin
/disk/tools/fs-NetBSD/mkboot/stage2/fs.h
0,0 → 1,752
/* $NetBSD: fs.h,v 1.56 2011/03/06 17:08:38 bouyer Exp $ */
 
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fs.h 8.13 (Berkeley) 3/21/95
*/
 
/*
* NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
*/
 
#ifndef _UFS_FFS_FS_H_
#define _UFS_FFS_FS_H_
 
/*
* Each disk drive contains some number of file systems.
* A file system consists of a number of cylinder groups.
* Each cylinder group has inodes and data.
*
* A file system is described by its super-block, which in turn
* describes the cylinder groups. The super-block is critical
* data and is replicated in each cylinder group to protect against
* catastrophic loss. This is done at `newfs' time and the critical
* super-block data does not change, so the copies need not be
* referenced further unless disaster strikes.
*
* For file system fs, the offsets of the various blocks of interest
* are given in the super block as:
* [fs->fs_sblkno] Super-block
* [fs->fs_cblkno] Cylinder group block
* [fs->fs_iblkno] Inode blocks
* [fs->fs_dblkno] Data blocks
* The beginning of cylinder group cg in fs, is given by
* the ``cgbase(fs, cg)'' macro.
*
* Depending on the architecture and the media, the superblock may
* reside in any one of four places. For tiny media where every block
* counts, it is placed at the very front of the partition. Historically,
* UFS1 placed it 8K from the front to leave room for the disk label and
* a small bootstrap. For UFS2 it got moved to 64K from the front to leave
* room for the disk label and a bigger bootstrap, and for really piggy
* systems we check at 256K from the front if the first three fail. In
* all cases the size of the superblock will be SBLOCKSIZE. All values are
* given in byte-offset form, so they do not imply a sector size. The
* SBLOCKSEARCH specifies the order in which the locations should be searched.
*
* Unfortunately the UFS2/FFSv2 change was done without adequate consideration
* of backward compatibility. In particular 'newfs' for a FFSv2 partition
* must overwrite any old FFSv1 superblock at 8k, and preferrably as many
* of the alternates as it can find - otherwise attempting to mount on a
* system that only supports FFSv1 is likely to succeed!.
* For a small FFSv1 filesystem, an old FFSv2 superblock can be left on
* the disk, and a system that tries to find an FFSv2 filesystem in preference
* to and FFSv1 one (as NetBSD does) can mount the old FFSv2 filesystem.
* As a added bonus, the 'first alternate' superblock of a FFSv1 filesystem
* with 64k blocks is at 64k - just where the code looks first when playing
* 'hunt the superblock'.
*
* The ffsv2 superblock layout (which might contain an ffsv1 filesystem)
* can be detected by checking for sb->fs_old_flags & FS_FLAGS_UPDATED.
* This is the default superblock type for NetBSD since ffsv2 support was added.
*/
#define BBSIZE 8192
#define BBOFF ((off_t)(0))
#define BBLOCK ((daddr_t)(0))
 
#define SBLOCK_FLOPPY 0
#define SBLOCK_UFS1 8192
#define SBLOCK_UFS2 65536
#define SBLOCK_PIGGY 262144
#define SBLOCKSIZE 8192
/*
* NB: Do not, under any circumstances, look for an ffsv1 filesystem at
* SBLOCK_UFS2. Doing so will find the wrong superblock for filesystems
* with a 64k block size.
*/
#define SBLOCKSEARCH \
{ SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
 
/*
* Max number of fragments per block. This value is NOT tweakable.
*/
#define MAXFRAG 8
 
 
 
/*
* Addresses stored in inodes are capable of addressing fragments
* of `blocks'. File system blocks of at most size MAXBSIZE can
* be optionally broken into 2, 4, or 8 pieces, each of which is
* addressable; these pieces may be DEV_BSIZE, or some multiple of
* a DEV_BSIZE unit.
*
* Large files consist of exclusively large data blocks. To avoid
* undue wasted disk space, the last data block of a small file may be
* allocated as only as many fragments of a large block as are
* necessary. The file system format retains only a single pointer
* to such a fragment, which is a piece of a single large block that
* has been divided. The size of such a fragment is determinable from
* information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
*
* The file system records space availability at the fragment level;
* to determine block availability, aligned fragments are examined.
*/
 
/*
* MINBSIZE is the smallest allowable block size.
* In order to insure that it is possible to create files of size
* 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
* MINBSIZE must be big enough to hold a cylinder group block,
* thus changes to (struct cg) must keep its size within MINBSIZE.
* Note that super blocks are always of size SBSIZE,
* and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
*/
#define MINBSIZE 4096
 
/*
* The path name on which the file system is mounted is maintained
* in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
* the super block for this name.
*/
#define MAXMNTLEN 468
 
/*
* The volume name for this filesystem is maintained in fs_volname.
* MAXVOLLEN defines the length of the buffer allocated.
* This space used to be part of of fs_fsmnt.
*/
#define MAXVOLLEN 32
 
/*
* There is a 128-byte region in the superblock reserved for in-core
* pointers to summary information. Originally this included an array
* of pointers to blocks of struct csum; now there are just four
* pointers and the remaining space is padded with fs_ocsp[].
* NOCSPTRS determines the size of this padding. One pointer (fs_csp)
* is taken away to point to a contiguous array of struct csum for
* all cylinder groups; a second (fs_maxcluster) points to an array
* of cluster sizes that is computed as cylinder groups are inspected;
* the third (fs_contigdirs) points to an array that tracks the
* creation of new directories; and the fourth (fs_active) is used
* by snapshots.
*/
#define NOCSPTRS ((128 / sizeof(void *)) - 4)
 
/*
* A summary of contiguous blocks of various sizes is maintained
* in each cylinder group. Normally this is set by the initial
* value of fs_maxcontig. To conserve space, a maximum summary size
* is set by FS_MAXCONTIG.
*/
#define FS_MAXCONTIG 16
 
/*
* The maximum number of snapshot nodes that can be associated
* with each filesystem. This limit affects only the number of
* snapshot files that can be recorded within the superblock so
* that they can be found when the filesystem is mounted. However,
* maintaining too many will slow the filesystem performance, so
* having this limit is a good idea.
*/
#define FSMAXSNAP 20
 
/*
* Used to identify special blocks in snapshots:
*
* BLK_NOCOPY - A block that was unallocated at the time the snapshot
* was taken, hence does not need to be copied when written.
* BLK_SNAP - A block held by another snapshot that is not needed by this
* snapshot. When the other snapshot is freed, the BLK_SNAP entries
* are converted to BLK_NOCOPY. These are needed to allow fsck to
* identify blocks that are in use by other snapshots (which are
* expunged from this snapshot).
*/
#define BLK_NOCOPY ((daddr_t)(1))
#define BLK_SNAP ((daddr_t)(2))
 
/*
* MINFREE gives the minimum acceptable percentage of file system
* blocks which may be free. If the freelist drops below this level
* only the superuser may continue to allocate blocks. This may
* be set to 0 if no reserve of free blocks is deemed necessary,
* however throughput drops by fifty percent if the file system
* is run at between 95% and 100% full; thus the minimum default
* value of fs_minfree is 5%. However, to get good clustering
* performance, 10% is a better choice. This value is used only
* when creating a file system and can be overriden from the
* command line. By default we choose to optimize for time.
*/
#define MINFREE 5
#define DEFAULTOPT FS_OPTTIME
 
/*
* Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
* tune the layout preferences for directories within a filesystem.
* His algorithm can be tuned by adjusting the following parameters
* which tell the system the average file size and the average number
* of files per directory. These defaults are well selected for typical
* filesystems, but may need to be tuned for odd cases like filesystems
* being used for squid caches or news spools.
*/
#define AVFILESIZ 16384 /* expected average file size */
#define AFPDIR 64 /* expected number of files per directory */
 
/*
* Per cylinder group information; summarized in blocks allocated
* from first cylinder group data blocks. These blocks have to be
* read in from fs_csaddr (size fs_cssize) in addition to the
* super block.
*/
struct csum {
int32_t cs_ndir; /* number of directories */
int32_t cs_nbfree; /* number of free blocks */
int32_t cs_nifree; /* number of free inodes */
int32_t cs_nffree; /* number of free frags */
};
 
struct csum_total {
int64_t cs_ndir; /* number of directories */
int64_t cs_nbfree; /* number of free blocks */
int64_t cs_nifree; /* number of free inodes */
int64_t cs_nffree; /* number of free frags */
int64_t cs_spare[4]; /* future expansion */
};
 
 
/*
* Super block for an FFS file system in memory.
*/
struct fs {
int32_t fs_firstfield; /* historic file system linked list, */
int32_t fs_unused_1; /* used for incore super blocks */
int32_t fs_sblkno; /* addr of super-block in filesys */
int32_t fs_cblkno; /* offset of cyl-block in filesys */
int32_t fs_iblkno; /* offset of inode-blocks in filesys */
int32_t fs_dblkno; /* offset of first data after cg */
int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */
int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */
int32_t fs_old_time; /* last time written */
int32_t fs_old_size; /* number of blocks in fs */
int32_t fs_old_dsize; /* number of data blocks in fs */
int32_t fs_ncg; /* number of cylinder groups */
int32_t fs_bsize; /* size of basic blocks in fs */
int32_t fs_fsize; /* size of frag blocks in fs */
int32_t fs_frag; /* number of frags in a block in fs */
/* these are configuration parameters */
int32_t fs_minfree; /* minimum percentage of free blocks */
int32_t fs_old_rotdelay; /* num of ms for optimal next block */
int32_t fs_old_rps; /* disk revolutions per second */
/* these fields can be computed from the others */
int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
int32_t fs_fshift; /* ``numfrags'' calc number of frags */
/* these are configuration parameters */
int32_t fs_maxcontig; /* max number of contiguous blks */
int32_t fs_maxbpg; /* max number of blks per cyl group */
/* these fields can be computed from the others */
int32_t fs_fragshift; /* block to frag shift */
int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t fs_sbsize; /* actual size of super block */
int32_t fs_spare1[2]; /* old fs_csmask */
/* old fs_csshift */
int32_t fs_nindir; /* value of NINDIR */
int32_t fs_inopb; /* value of INOPB */
int32_t fs_old_nspf; /* value of NSPF */
/* yet another configuration parameter */
int32_t fs_optim; /* optimization preference, see below */
/* these fields are derived from the hardware */
int32_t fs_old_npsect; /* # sectors/track including spares */
int32_t fs_old_interleave; /* hardware sector interleave */
int32_t fs_old_trackskew; /* sector 0 skew, per track */
/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
int32_t fs_id[2]; /* unique file system id */
/* sizes determined by number of cylinder groups and their sizes */
int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */
int32_t fs_cssize; /* size of cyl grp summary area */
int32_t fs_cgsize; /* cylinder group size */
/* these fields are derived from the hardware */
int32_t fs_spare2; /* old fs_ntrak */
int32_t fs_old_nsect; /* sectors per track */
int32_t fs_old_spc; /* sectors per cylinder */
int32_t fs_old_ncyl; /* cylinders in file system */
int32_t fs_old_cpg; /* cylinders per group */
int32_t fs_ipg; /* inodes per group */
int32_t fs_fpg; /* blocks per group * fs_frag */
/* this data must be re-computed after crashes */
struct csum fs_old_cstotal; /* cylinder summary information */
/* these fields are cleared at mount time */
int8_t fs_fmod; /* super block modified flag */
uint8_t fs_clean; /* file system is clean flag */
int8_t fs_ronly; /* mounted read-only flag */
uint8_t fs_old_flags; /* see FS_ flags below */
u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
u_char fs_volname[MAXVOLLEN]; /* volume name */
uint64_t fs_swuid; /* system-wide uid */
int32_t fs_pad;
/* these fields retain the current block allocation info */
int32_t fs_cgrotor; /* last cg searched (UNUSED) */
void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
u_int8_t *fs_contigdirs; /* # of contiguously allocated dirs */
struct csum *fs_csp; /* cg summary info buffer for fs_cs */
int32_t *fs_maxcluster; /* max cluster in each cyl group */
u_char *fs_active; /* used by snapshots to track fs */
int32_t fs_old_cpc; /* cyl per cycle in postbl */
/* this area is otherwise allocated unless fs_old_flags & FS_FLAGS_UPDATED */
int32_t fs_maxbsize; /* maximum blocking factor permitted */
uint8_t fs_journal_version; /* journal format version */
uint8_t fs_journal_location; /* journal location type */
uint8_t fs_journal_reserved[2];/* reserved for future use */
uint32_t fs_journal_flags; /* journal flags */
uint64_t fs_journallocs[4]; /* location info for journal */
uint32_t fs_quota_magic; /* see quota2.h */
uint8_t fs_quota_flags; /* see quota2.h */
uint8_t fs_quota_reserved[3];
uint64_t fs_quotafile[2]; /* pointer to quota inodes */
int64_t fs_sparecon64[9]; /* reserved for future use */
int64_t fs_sblockloc; /* byte offset of standard superblock */
struct csum_total fs_cstotal; /* cylinder summary information */
int64_t fs_time; /* last time written */
int64_t fs_size; /* number of blocks in fs */
int64_t fs_dsize; /* number of data blocks in fs */
int64_t fs_csaddr; /* blk addr of cyl grp summary area */
int64_t fs_pendingblocks; /* blocks in process of being freed */
int32_t fs_pendinginodes; /* inodes in process of being freed */
int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
/* back to stuff that has been around a while */
int32_t fs_avgfilesize; /* expected average file size */
int32_t fs_avgfpdir; /* expected # of files per directory */
int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
int32_t fs_sparecon32[26]; /* reserved for future constants */
uint32_t fs_flags; /* see FS_ flags below */
/* back to stuff that has been around a while (again) */
int32_t fs_contigsumsize; /* size of cluster summary array */
int32_t fs_maxsymlinklen; /* max length of an internal symlink */
int32_t fs_old_inodefmt; /* format of on-disk inodes */
u_int64_t fs_maxfilesize; /* maximum representable file size */
int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
int32_t fs_state; /* validate fs_clean field (UNUSED) */
int32_t fs_old_postblformat; /* format of positional layout tables */
int32_t fs_old_nrpos; /* number of rotational positions */
int32_t fs_spare5[2]; /* old fs_postbloff */
/* old fs_rotbloff */
int32_t fs_magic; /* magic number */
};
 
#define fs_old_postbloff fs_spare5[0]
#define fs_old_rotbloff fs_spare5[1]
#define fs_old_postbl_start fs_maxbsize
#define fs_old_headswitch fs_id[0]
#define fs_old_trkseek fs_id[1]
#define fs_old_csmask fs_spare1[0]
#define fs_old_csshift fs_spare1[1]
 
#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
 
#define old_fs_postbl(fs_, cylno, opostblsave) \
((((fs_)->fs_old_postblformat == FS_42POSTBLFMT) || \
((fs_)->fs_old_postbloff == offsetof(struct fs, fs_old_postbl_start))) \
? ((int16_t *)(opostblsave) + (cylno) * (fs_)->fs_old_nrpos) \
: ((int16_t *)((uint8_t *)(fs_) + \
(fs_)->fs_old_postbloff) + (cylno) * (fs_)->fs_old_nrpos))
#define old_fs_rotbl(fs) \
(((fs)->fs_old_postblformat == FS_42POSTBLFMT) \
? ((uint8_t *)(&(fs)->fs_magic+1)) \
: ((uint8_t *)((uint8_t *)(fs) + (fs)->fs_old_rotbloff)))
 
/*
* File system identification
*/
#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast file system magic number */
#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast file system magic number */
#define FS_UFS1_MAGIC_SWAPPED 0x54190100
#define FS_UFS2_MAGIC_SWAPPED 0x19015419
#define FS_OKAY 0x7c269d38 /* superblock checksum */
#define FS_42INODEFMT -1 /* 4.2BSD inode format */
#define FS_44INODEFMT 2 /* 4.4BSD inode format */
 
/*
* File system clean flags
*/
#define FS_ISCLEAN 0x01
#define FS_WASCLEAN 0x02
 
/*
* Preference for optimization.
*/
#define FS_OPTTIME 0 /* minimize allocation time */
#define FS_OPTSPACE 1 /* minimize disk fragmentation */
 
/*
* File system flags
*/
#define FS_UNCLEAN 0x001 /* file system not clean at mount (unused) */
#define FS_DOSOFTDEP 0x002 /* file system using soft dependencies */
#define FS_NEEDSFSCK 0x004 /* needs sync fsck (FreeBSD compat, unused) */
#define FS_INDEXDIRS 0x008 /* kernel supports indexed directories */
#define FS_ACLS 0x010 /* file system has ACLs enabled */
#define FS_MULTILABEL 0x020 /* file system is MAC multi-label */
#define FS_GJOURNAL 0x40 /* gjournaled file system */
#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
#define FS_DOWAPBL 0x100 /* Write ahead physical block logging */
#define FS_DOQUOTA2 0x200 /* in-filesystem quotas */
 
/* File system flags that are ok for NetBSD if set in fs_flags */
#define FS_KNOWN_FLAGS (FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2)
 
/*
* File system internal flags, also in fs_flags.
* (Pick highest number to avoid conflicts with others)
*/
#define FS_SWAPPED 0x80000000 /* file system is endian swapped */
#define FS_INTERNAL 0x80000000 /* mask for internal flags */
 
/*
* Macros to access bits in the fs_active array.
*/
#define ACTIVECG_SET(fs, cg) \
do { \
if ((fs)->fs_active != NULL) \
setbit((fs)->fs_active, (cg)); \
} while (/*CONSTCOND*/ 0)
#define ACTIVECG_CLR(fs, cg) \
do { \
if ((fs)->fs_active != NULL) \
clrbit((fs)->fs_active, (cg)); \
} while (/*CONSTCOND*/ 0)
#define ACTIVECG_ISSET(fs, cg) \
((fs)->fs_active != NULL && isset((fs)->fs_active, (cg)))
 
/*
* The size of a cylinder group is calculated by CGSIZE. The maximum size
* is limited by the fact that cylinder groups are at most one block.
* Its size is derived from the size of the maps maintained in the
* cylinder group and the (struct cg) size.
*/
#define CGSIZE_IF(fs, ipg, fpg) \
/* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \
/* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \
/* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \
/* inode map */ howmany((ipg), NBBY) + \
/* block map */ howmany((fpg), NBBY) +\
/* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
/* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \
/* cluster map */ howmany(fragstoblks(fs, (fpg)), NBBY)))
 
#define CGSIZE(fs) CGSIZE_IF((fs), (fs)->fs_ipg, (fs)->fs_fpg)
 
/*
* The minimal number of cylinder groups that should be created.
*/
#define MINCYLGRPS 4
 
 
/*
* Convert cylinder group to base address of its global summary info.
*/
#define fs_cs(fs, indx) fs_csp[indx]
 
/*
* Cylinder group block for a file system.
*/
#define CG_MAGIC 0x090255
struct cg {
int32_t cg_firstfield; /* historic cyl groups linked list */
int32_t cg_magic; /* magic number */
int32_t cg_old_time; /* time last written */
int32_t cg_cgx; /* we are the cgx'th cylinder group */
int16_t cg_old_ncyl; /* number of cyl's this cg */
int16_t cg_old_niblk; /* number of inode blocks this cg */
int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int32_t cg_rotor; /* position of last used block */
int32_t cg_frotor; /* position of last used frag */
int32_t cg_irotor; /* position of last used inode */
int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
int32_t cg_old_btotoff; /* (int32) block totals per cylinder */
int32_t cg_old_boff; /* (u_int16) free block positions */
int32_t cg_iusedoff; /* (u_int8) used inode map */
int32_t cg_freeoff; /* (u_int8) free block map */
int32_t cg_nextfreeoff; /* (u_int8) next available space */
int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */
int32_t cg_clusteroff; /* (u_int8) free cluster map */
int32_t cg_nclusterblks; /* number of clusters this cg */
int32_t cg_niblk; /* number of inode blocks this cg */
int32_t cg_initediblk; /* last initialized inode */
int32_t cg_sparecon32[3]; /* reserved for future use */
int64_t cg_time; /* time last written */
int64_t cg_sparecon64[3]; /* reserved for future use */
u_int8_t cg_space[1]; /* space for cylinder group maps */
/* actually longer */
};
 
/*
* The following structure is defined
* for compatibility with old file systems.
*/
struct ocg {
int32_t cg_firstfield; /* historic linked list of cyl groups */
int32_t cg_unused_1; /* used for incore cyl groups */
int32_t cg_time; /* time last written */
int32_t cg_cgx; /* we are the cgx'th cylinder group */
int16_t cg_ncyl; /* number of cyl's this cg */
int16_t cg_niblk; /* number of inode blocks this cg */
int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int32_t cg_rotor; /* position of last used block */
int32_t cg_frotor; /* position of last used frag */
int32_t cg_irotor; /* position of last used inode */
int32_t cg_frsum[8]; /* counts of available frags */
int32_t cg_btot[32]; /* block totals per cylinder */
int16_t cg_b[32][8]; /* positions of free blocks */
u_int8_t cg_iused[256]; /* used inode map */
int32_t cg_magic; /* magic number */
u_int8_t cg_free[1]; /* free block map */
/* actually longer */
};
 
 
/*
* Macros for access to cylinder group array structures.
*/
#define old_cg_blktot_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_btot)
#define old_cg_blks_old(fs, cgp, cylno, ns) \
(((struct ocg *)(cgp))->cg_b[cylno])
 
#define old_cg_blktot_new(cgp, ns) \
((int32_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_old_btotoff, (ns))))
#define old_cg_blks_new(fs, cgp, cylno, ns) \
((int16_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_old_boff, (ns))) + (cylno) * (fs)->fs_old_nrpos)
 
#define old_cg_blktot(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
old_cg_blktot_old(cgp, ns) : old_cg_blktot_new(cgp, ns))
#define old_cg_blks(fs, cgp, cylno, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
old_cg_blks_old(fs, cgp, cylno, ns) : old_cg_blks_new(fs, cgp, cylno, ns))
 
#define cg_inosused_new(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_iusedoff, (ns))))
#define cg_blksfree_new(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_freeoff, (ns))))
#define cg_chkmagic_new(cgp, ns) \
(ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
 
#define cg_inosused_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_iused)
#define cg_blksfree_old(cgp, ns) \
(((struct ocg *)(cgp))->cg_free)
#define cg_chkmagic_old(cgp, ns) \
(ufs_rw32(((struct ocg *)(cgp))->cg_magic, (ns)) == CG_MAGIC)
 
#define cg_inosused(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
cg_inosused_old(cgp, ns) : cg_inosused_new(cgp, ns))
#define cg_blksfree(cgp, ns) \
((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
cg_blksfree_old(cgp, ns) : cg_blksfree_new(cgp, ns))
#define cg_chkmagic(cgp, ns) \
(cg_chkmagic_new(cgp, ns) || cg_chkmagic_old(cgp, ns))
 
#define cg_clustersfree(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_clusteroff, (ns))))
#define cg_clustersum(cgp, ns) \
((int32_t *)((u_int8_t *)(cgp) + \
ufs_rw32((cgp)->cg_clustersumoff, (ns))))
 
 
/*
* Turn file system block numbers into disk block addresses.
* This maps file system blocks to device size blocks.
*/
#if defined (_KERNEL)
#define fsbtodb(fs, b) ((b) << ((fs)->fs_fshift - DEV_BSHIFT))
#define dbtofsb(fs, b) ((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
#else
#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
#endif
 
/*
* Cylinder group macros to locate things in cylinder groups.
* They calc file system addresses of cylinder group data structures.
*/
#define cgbase(fs, c) (((daddr_t)(fs)->fs_fpg) * (c))
#define cgstart_ufs1(fs, c) \
(cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))
#define cgstart_ufs2(fs, c) cgbase((fs), (c))
#define cgstart(fs, c) ((fs)->fs_magic == FS_UFS2_MAGIC \
? cgstart_ufs2((fs), (c)) : cgstart_ufs1((fs), (c)))
#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
 
/*
* Macros for handling inode numbers:
* inode number to file system block offset.
* inode number to cylinder group number.
* inode number to file system block address.
*/
#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
#define ino_to_fsba(fs, x) \
((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
 
/*
* Give cylinder group number for a file system block.
* Give cylinder group block number for a file system block.
*/
#define dtog(fs, d) ((d) / (fs)->fs_fpg)
#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
 
/*
* Extract the bits for a block from a map.
* Compute the cylinder and rotational position of a cyl block addr.
*/
#define blkmap(fs, map, loc) \
(((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
#define old_cbtocylno(fs, bno) \
(fsbtodb(fs, bno) / (fs)->fs_old_spc)
#define old_cbtorpos(fs, bno) \
((fs)->fs_old_nrpos <= 1 ? 0 : \
(fsbtodb(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
fsbtodb(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
(fs)->fs_old_nsect * (fs)->fs_old_nrpos / (fs)->fs_old_npsect)
 
/*
* The following macros optimize certain frequently calculated
* quantities by using shifts and masks in place of divisions
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
((loc) & (fs)->fs_qbmask)
#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
((loc) & (fs)->fs_qfmask)
#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
(((off_t)(frag)) << (fs)->fs_fshift)
#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
(((off_t)(blk)) << (fs)->fs_bshift)
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
((loc) >> (fs)->fs_bshift)
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
((loc) >> (fs)->fs_fshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
(((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
(((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
((frags) >> (fs)->fs_fragshift)
#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
((blks) << (fs)->fs_fragshift)
#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
((fsb) & ((fs)->fs_frag - 1))
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
((fsb) &~ ((fs)->fs_frag - 1))
 
/*
* Determine the number of available frags given a
* percentage to hold in reserve.
*/
#define freespace(fs, percentreserved) \
(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
(fs)->fs_cstotal.cs_nffree - \
(((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
 
/*
* Determining the size of a file block in the file system.
*/
#define blksize(fs, ip, lbn) \
(((lbn) >= NDADDR || (ip)->i_size >= lblktosize(fs, (lbn) + 1)) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_size))))
 
#define sblksize(fs, size, lbn) \
(((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (size)))))
 
 
/*
* Number of inodes in a secondary storage block/fragment.
*/
#define INOPB(fs) ((fs)->fs_inopb)
#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
 
/*
* Number of indirects in a file system block.
*/
#define NINDIR(fs) ((fs)->fs_nindir)
 
/*
* Apple UFS Label:
* We check for this to decide to use APPLEUFS_DIRBLKSIZ
*/
#define APPLEUFS_LABEL_MAGIC 0x4c41424c /* LABL */
#define APPLEUFS_LABEL_SIZE 1024
#define APPLEUFS_LABEL_OFFSET (BBSIZE - APPLEUFS_LABEL_SIZE) /* located at 7k */
#define APPLEUFS_LABEL_VERSION 1
#define APPLEUFS_MAX_LABEL_NAME 512
 
struct appleufslabel {
u_int32_t ul_magic;
u_int16_t ul_checksum;
u_int16_t ul_unused0;
u_int32_t ul_version;
u_int32_t ul_time;
u_int16_t ul_namelen;
u_char ul_name[APPLEUFS_MAX_LABEL_NAME]; /* Warning: may not be null terminated */
u_int16_t ul_unused1;
u_int64_t ul_uuid; /* Note this is only 4 byte aligned */
u_char ul_reserved[24];
u_char ul_unused[460];
} __packed;
 
 
#endif /* !_UFS_FFS_FS_H_ */
/disk/tools/fs-NetBSD/mkboot/Makefile
0,0 → 1,28
#
# Makefile to build the boot block (with an empty disklabel)
#
 
BUILD = ../../../../build
 
.PHONY: all install clean
 
all: bootblk
 
install: bootblk
mkdir -p $(BUILD)/run/fs-NetBSD
cp bootblk $(BUILD)/run/fs-NetBSD
 
bootblk: stage1/br.bin stage2/boot.bin
dd if=/dev/zero of=./zeroes bs=512 count=1
cat stage1/br.bin zeroes stage2/boot.bin >bootblk
 
stage1/br.bin:
$(MAKE) -C stage1
 
stage2/boot.bin:
$(MAKE) -C stage2
 
clean:
$(MAKE) -C stage1 clean
$(MAKE) -C stage2 clean
rm -f *~ zeroes bootblk
/disk/tools/fs-NetBSD/wrboot/Makefile
0,0 → 1,36
#
# Makefile for wrboot utility
#
 
BUILD = ../../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = wrboot.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = NetBSD-wrboot
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/tools/fs-NetBSD/wrboot/wrboot.c
0,0 → 1,144
/*
* wrboot.c -- write the boot block
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
 
 
/**************************************************************/
 
 
#define SSIZE 512 /* disk sector size in bytes */
#define BSIZE 8192 /* disk block size in bytes */
 
 
/**************************************************************/
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
printf("Error: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
exit(1);
}
 
 
/**************************************************************/
 
 
unsigned int read4FromEco(unsigned char *p) {
return (unsigned int) p[0] << 24 |
(unsigned int) p[1] << 16 |
(unsigned int) p[2] << 8 |
(unsigned int) p[3] << 0;
}
 
 
/**************************************************************/
 
 
void usage(char *myself) {
printf("Usage: %s <bootblock> <disk> <partition or '*'>\n", myself);
}
 
 
int main(int argc, char *argv[]) {
int i;
char *bootName;
FILE *bootFile;
int bootSize;
char *diskName;
FILE *diskFile;
unsigned long sliceStart;
unsigned long sliceSize;
int part;
char *endptr;
unsigned char partTable[SSIZE];
unsigned char *ptptr;
unsigned long partType;
unsigned char bootCode[BSIZE];
unsigned char diskLabel[SSIZE];
 
if (argc != 4) {
usage(argv[0]);
exit(1);
}
/* read bootblock from file */
for (i = 0; i < BSIZE; i++) {
bootCode[i] = 0;
}
bootName = argv[1];
bootFile = fopen(bootName, "rb");
if (bootFile == NULL) {
error("cannot open bootblock '%s'", bootName);
}
fseek(bootFile, 0, SEEK_END);
bootSize = ftell(bootFile);
fseek(bootFile, 0, SEEK_SET);
if (bootSize > BSIZE) {
error("bootblock '%s' too big", bootName);
}
if (fread(bootCode, 1, bootSize, bootFile) != bootSize) {
error("cannot read bootblock '%s'", bootName);
}
fclose(bootFile);
printf("Bootblock '%s' read, %d bytes.\n", bootName, bootSize);
/* determine NetBSD slice position on disk */
diskName = argv[2];
diskFile = fopen(diskName, "r+b");
if (diskFile == NULL) {
error("cannot open disk image '%s'", diskName);
}
if (strcmp(argv[3], "*") == 0) {
/* whole disk contains one single slice */
sliceStart = 0;
fseek(diskFile, 0, SEEK_END);
sliceSize = ftell(diskFile) / SSIZE;
} else {
/* argv[3] is partition number of NetBSD slice */
part = strtoul(argv[3], &endptr, 10);
if (*endptr != '\0' || part < 0 || part > 15) {
error("illegal partition number '%s'", argv[3]);
}
fseek(diskFile, 1 * SSIZE, SEEK_SET);
if (fread(partTable, 1, SSIZE, diskFile) != SSIZE) {
error("cannot read partition table of disk '%s'", diskName);
}
ptptr = partTable + part * 32;
partType = read4FromEco(ptptr + 0);
if ((partType & 0x7FFFFFFF) != 0x000000A9) {
error("partition %d of disk '%s' is not a NetBSD slice",
part, diskName);
}
sliceStart = read4FromEco(ptptr + 4);
sliceSize = read4FromEco(ptptr + 8);
}
printf("Slice size is %lu (0x%lX) sectors of %d bytes each.\n",
sliceSize, sliceSize, SSIZE);
/* read disklabel from disk */
fseek(diskFile, (sliceStart + 1) * SSIZE, SEEK_SET);
if (fread(diskLabel, 1, SSIZE, diskFile) != SSIZE) {
error("cannot read disklabel of disk '%s'", diskName);
}
printf("Disklabel read from disk '%s', %d bytes\n", diskName, SSIZE);
/* copy disklabel to bootblock in memory */
for (i = 0; i < SSIZE; i++) {
bootCode[SSIZE + i] = diskLabel[i];
}
/* write bootblock to disk */
fseek(diskFile, (sliceStart + 0) * SSIZE, SEEK_SET);
if (fwrite(bootCode, 1, bootSize, diskFile) != bootSize) {
error("cannot write bootblock to disk '%s'", diskName);
}
printf("Bootblock written to disk '%s', %d bytes\n", diskName, bootSize);
fclose(diskFile);
return 0;
}
/disk/tools/fs-NetBSD/Makefile
0,0 → 1,27
#
# Makefile for NetBSD disk tools
#
 
BUILD = ../../../build
 
DIRS = dsklbl mkboot wrboot makefs loader
 
.PHONY: all install clean
 
all:
for i in $(DIRS) ; do \
$(MAKE) -C $$i all ; \
done
 
install:
for i in $(DIRS) ; do \
$(MAKE) -C $$i install ; \
done
mkdir -p $(BUILD)/run/fs-NetBSD
cp Makefile.run $(BUILD)/run/fs-NetBSD/Makefile
 
clean:
for i in $(DIRS) ; do \
$(MAKE) -C $$i clean ; \
done
rm -f *~
/disk/tools/mkmboot/stage1/mbr.s
0,0 → 1,127
;
; mbr.s -- the master boot record
;
 
; Runtime environment:
;
; This code must be loaded and started at 0xC0000000.
; It allocates a stack from 0xC0001000 downwards. So
; it must run within 4K (code + data + stack).
;
; This code expects the disk number of the boot disk
; in $16, the start sector of the disk or partition
; to be booted in $17 and its size in $18.
;
; The boot manager, which is loaded by this code,
; must be in standalone (headerless) executable
; format, stored at absolute disk sectors 2..31,
; and gets loaded and started at 0xC0001000.
 
.set stacktop,0xC0001000 ; top of stack
.set loadaddr,0xC0001000 ; where to load the boot manager
 
.set cout,0xE0000018 ; ROM console output
.set dskio,0xE0000030 ; ROM disk I/O
 
; reset arrives here
reset:
j start
 
; interrupts arrive here
intrpt:
j userMiss
 
; user TLB misses arrive here
userMiss:
add $4,$0,intmsg ; we do not expect any interrupt
jal msgout
j halt
 
; load the boot manager and start it
start:
add $29,$0,stacktop ; setup stack
add $4,$0,strtmsg ; say what is going on
jal msgout
add $4,$0,2 ; start loading with sector 2
add $5,$0,loadaddr ; where to load the boot manager
and $5,$5,0x3FFFFFFF ; convert to physical address
add $6,$0,30 ; 30 sectors to load
jal rdsct
add $8,$0,loadaddr ; start executing the boot manager
jr $8
 
; read disk sectors
; $4 start sector number (disk or partition relative)
; $5 transfer address
; $6 number of sectors
rdsct:
sub $29,$29,32
stw $31,$29,20
stw $6,$29,16 ; sector count
add $7,$5,$0 ; transfer address
add $6,$4,$17 ; relative sector -> absolute
add $5,$0,'r' ; command
add $4,$0,$16 ; disk number
add $8,$0,dskio
jalr $8
bne $2,$0,rderr ; error?
ldw $31,$29,20
add $29,$29,32
jr $31
 
; disk read error
rderr:
add $4,$0,dremsg
jal msgout
j halt
 
; output message
; $4 pointer to string
msgout:
sub $29,$29,8
stw $31,$29,4
stw $16,$29,0
add $16,$4,0 ; $16: pointer to string
msgout1:
ldbu $4,$16,0 ; get character
beq $4,$0,msgout2 ; done?
jal chrout ; output character
add $16,$16,1 ; bump pointer
j msgout1 ; continue
msgout2:
ldw $16,$29,0
ldw $31,$29,4
add $29,$29,8
jr $31
 
; output character
; $4 character
chrout:
sub $29,$29,4
stw $31,$29,0
add $8,$0,cout
jalr $8
ldw $31,$29,0
add $29,$29,4
jr $31
 
; halt execution by looping
halt:
add $4,$0,hltmsg
jal msgout
halt1:
j halt1
 
; messages
intmsg:
.byte "unexpected interrupt", 0x0D, 0x0A, 0
strtmsg:
.byte "MBR executing...", 0x0D, 0x0A, 0
dremsg:
.byte "disk read error", 0x0D, 0x0A, 0
hltmsg:
.byte "bootstrap halted", 0x0D, 0x0A, 0
 
; boot record signature
.locate 512-2
.byte 0x55, 0xAA
/disk/tools/mkmboot/stage1/Makefile
0,0 → 1,16
#
# Makefile to build the master boot record
#
 
BUILD = ../../../../build
 
all: mbr.bin
 
mbr.bin: mbr.o
$(BUILD)/bin/ld -h -rc 0xC0000000 -o mbr.bin mbr.o
 
mbr.o: mbr.s
$(BUILD)/bin/as -o mbr.o mbr.s
 
clean:
rm -f *~ mbr.o mbr.bin
/disk/tools/mkmboot/stage2/biolib.s
0,0 → 1,26
;
; biolib.s -- basic I/O library
;
 
.set cin,0xE0000010
.set cout,0xE0000018
.set dskio,0xE0000030
 
.export getc
.export putc
.export rwscts
 
.code
.align 4
 
getc:
add $8,$0,cin
jr $8
 
putc:
add $8,$0,cout
jr $8
 
rwscts:
add $8,$0,dskio
jr $8
/disk/tools/mkmboot/stage2/mboot.c
0,0 → 1,271
/*
* mboot.c -- the master bootstrap (boot manager)
*/
 
 
#include "stdarg.h"
#include "biolib.h"
 
 
#define DEFAULT_PARTITION "" /* default boot partition number */
 
#define LINE_SIZE 80
#define SECTOR_SIZE 512
#define NPE (SECTOR_SIZE / sizeof(PartEntry))
#define DESCR_SIZE 20
 
 
unsigned int bootDisk = 0; /* gets loaded by previous stage */
unsigned int startSector = 0; /* gets loaded by previous stage */
unsigned int numSectors = 0; /* gets loaded by previous stage */
 
 
typedef struct {
unsigned long type;
unsigned long start;
unsigned long size;
char descr[DESCR_SIZE];
} PartEntry;
 
PartEntry ptr[NPE];
 
 
int strlen(char *str) {
int i;
 
i = 0;
while (*str++ != '\0') {
i++;
}
return i;
}
 
 
void strcpy(char *dst, char *src) {
while ((*dst++ = *src++) != '\0') ;
}
 
 
char getchar(void) {
return getc();
}
 
 
void putchar(char c) {
if (c == '\n') {
putchar('\r');
}
putc(c);
}
 
 
void puts(char *s) {
char c;
 
while ((c = *s++) != '\0') {
putchar(c);
}
}
 
 
void getline(char *prompt, char *line, int n) {
int i;
char c;
 
puts(prompt);
puts(line);
i = strlen(line);
while (i < n - 1) {
c = getchar();
if (c >= ' ' && c < 0x7F) {
putchar(c);
line[i] = c;
i++;
} else
if (c == '\r') {
putchar('\n');
line[i] = '\0';
i = n - 1;
} else
if (c == '\b' || c == 0x7F) {
if (i > 0) {
putchar('\b');
putchar(' ');
putchar('\b');
i--;
}
}
}
line[n - 1] = '\0';
}
 
 
int countPrintn(long n) {
long a;
int res;
 
res = 0;
if (n < 0) {
res++;
n = -n;
}
a = n / 10;
if (a != 0) {
res += countPrintn(a);
}
return res + 1;
}
 
 
void printn(long n) {
long a;
 
if (n < 0) {
putchar('-');
n = -n;
}
a = n / 10;
if (a != 0) {
printn(a);
}
putchar(n % 10 + '0');
}
 
 
void printf(char *fmt, ...) {
va_list ap;
char c;
int n;
unsigned int u;
char *s;
char filler;
int width, count, i;
 
va_start(ap, fmt);
while (1) {
while ((c = *fmt++) != '%') {
if (c == '\0') {
va_end(ap);
return;
}
putchar(c);
}
c = *fmt++;
if (c == '0') {
filler = '0';
c = *fmt++;
} else {
filler = ' ';
}
width = 0;
if (c >= '0' && c <= '9') {
width = c - '0';
c = *fmt++;
}
if (c == 'd') {
n = va_arg(ap, int);
if (width > 0) {
count = countPrintn(n);
for (i = 0; i < width - count; i++) {
putchar(filler);
}
}
printn(n);
} else
if (c == 's') {
s = va_arg(ap, char *);
puts(s);
} else
if (c == 'c') {
c = va_arg(ap, char);
putchar(c);
} else {
putchar(c);
}
}
}
 
 
void halt(void) {
printf("bootstrap halted\n");
while (1) ;
}
 
 
void readDisk(unsigned int sector, unsigned char *buffer, int count) {
int result;
 
if (sector + count > numSectors) {
printf("sector number exceeds disk or partition size\n");
halt();
}
result = rwscts(bootDisk, 'r', sector + startSector,
(unsigned int) buffer & 0x3FFFFFFF, count);
if (result != 0) {
printf("disk read error\n");
halt();
}
}
 
 
unsigned int entryPoint; /* where to continue from main() */
 
 
int main(void) {
int i;
char line[LINE_SIZE];
char *p;
int part;
 
printf("Bootstrap manager executing...\n");
strcpy(line, DEFAULT_PARTITION);
readDisk(1, (unsigned char *) ptr, 1);
while (1) {
printf("\nPartitions:\n");
printf(" # | b | description\n");
printf("---+---+----------------------\n");
for (i = 0; i < NPE; i++) {
if (ptr[i].type != 0) {
printf("%2d | %s | %s\n",
i, ptr[i].type & 0x80000000 ? "*" : " ", ptr[i].descr);
}
}
getline("\nBoot partition #: ", line, LINE_SIZE);
part = 0;
if (line[0] == '\0') {
continue;
}
p = line;
while (*p >= '0' && *p <= '9') {
part = part * 10 + (*p - '0');
p++;
}
if (*p != '\0' || part < 0 || part > 15) {
printf("illegal partition number\n");
continue;
}
if ((ptr[part].type & 0x7FFFFFFF) == 0) {
printf("partition %d does not contain a file system\n", part);
continue;
}
if ((ptr[part].type & 0x80000000) == 0) {
printf("partition %d is not bootable\n", part);
continue;
}
/* load boot sector of selected partition */
readDisk(ptr[part].start, (unsigned char *) 0xC0000000, 1);
/* check for signature */
if ((*((unsigned char *) 0xC0000000 + SECTOR_SIZE - 2) != 0x55) ||
(*((unsigned char *) 0xC0000000 + SECTOR_SIZE - 1) != 0xAA)) {
printf("boot sector of partition %d has no signature\n", part);
continue;
}
/* we have a valid boot sector, leave loop */
break;
}
/* boot manager finished, now go executing loaded boot sector */
startSector = ptr[part].start;
numSectors = ptr[part].size;
entryPoint = 0xC0000000;
return 0;
}
/disk/tools/mkmboot/stage2/c0.s
0,0 → 1,59
;
; c0.s -- startup code and begin-of-segment labels
;
 
.import main
 
.import _ecode
.import _edata
.import _ebss
 
.export _bcode
.export _bdata
.export _bbss
 
.import bootDisk
.import startSector
.import numSectors
.import entryPoint
 
.code
_bcode:
 
start:
add $10,$0,_bdata ; copy data segment
add $8,$0,_edata
sub $9,$8,$10
add $9,$9,_ecode
j cpytest
cpyloop:
ldw $11,$9,0
stw $11,$8,0
cpytest:
sub $8,$8,4
sub $9,$9,4
bgeu $8,$10,cpyloop
add $8,$0,_bbss ; clear bss segment
add $9,$0,_ebss
j clrtest
clrloop:
stw $0,$8,0
add $8,$8,4
clrtest:
bltu $8,$9,clrloop
add $29,$0,0xC0010000 ; setup stack
stw $16,$0,bootDisk ; make arguments available
stw $17,$0,startSector
stw $18,$0,numSectors
jal main ; call 'main' function
ldw $16,$0,bootDisk ; setup arguments for next stage
ldw $17,$0,startSector
ldw $18,$0,numSectors
ldw $31,$0,entryPoint ; jump to loaded program
jr $31
 
.data
_bdata:
 
.bss
_bbss:
/disk/tools/mkmboot/stage2/c1.s
0,0 → 1,19
;
; c1.s -- end-of-segment labels
;
 
.export _ecode
.export _edata
.export _ebss
 
.code
.align 4
_ecode:
 
.data
.align 4
_edata:
 
.bss
.align 4
_ebss:
/disk/tools/mkmboot/stage2/biolib.h
0,0 → 1,15
/*
* biolib.h -- basic I/O library
*/
 
 
#ifndef _BIOLIB_H_
#define _BIOLIB_H_
 
 
char getc(void);
void putc(char c);
int rwscts(int dskno, int cmd, int sector, int addr, int count);
 
 
#endif /* _BIOLIB_H_ */
/disk/tools/mkmboot/stage2/stdarg.h
0,0 → 1,41
/*
* stdarg.h -- variable argument lists
*/
 
 
#ifndef _STDARG_H_
#define _STDARG_H_
 
 
typedef char *va_list;
 
 
static float __va_arg_tmp;
 
 
#define va_start(list, start) \
((void)((list) = (sizeof(start)<4 ? \
(char *)((int *)&(start)+1) : (char *)(&(start)+1))))
 
#define __va_arg(list, mode, n) \
(__typecode(mode)==1 && sizeof(mode)==4 ? \
(__va_arg_tmp = *(double *)(&(list += \
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \
*(mode *)&__va_arg_tmp) : \
*(mode *)(&(list += \
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)]))
 
#define _bigendian_va_arg(list, mode, n) \
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \
__va_arg(list, mode, n))
 
#define va_end(list) ((void)0)
 
#define va_arg(list, mode) \
(sizeof(mode)==8 ? \
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \
_bigendian_va_arg(list, mode, 3U))
 
 
#endif /* _STDARG_H_ */
/disk/tools/mkmboot/stage2/Makefile
0,0 → 1,26
#
# Makefile to build the master bootstrap (boot manager)
#
 
BUILD = ../../../../build
 
all: mboot.bin
 
mboot.bin: c0.o mboot.o biolib.o c1.o
$(BUILD)/bin/ld -h -rc 0xC0001000 -o mboot.bin \
c0.o mboot.o biolib.o c1.o
 
c0.o: c0.s
$(BUILD)/bin/as -o c0.o c0.s
 
mboot.o: mboot.c
$(BUILD)/bin/lcc -A -c -o mboot.o mboot.c
 
biolib.o: biolib.s
$(BUILD)/bin/as -o biolib.o biolib.s
 
c1.o: c1.s
$(BUILD)/bin/as -o c1.o c1.s
 
clean:
rm -f *~ c0.o mboot.o biolib.o c1.o mboot.bin
/disk/tools/mkmboot/Makefile
0,0 → 1,28
#
# Makefile to build the master boot block (with an empty partition table)
#
 
BUILD = ../../../build
 
.PHONY: all install clean
 
all: mbootblk
 
install: mbootblk
mkdir -p $(BUILD)/run
cp mbootblk $(BUILD)/run
 
mbootblk: stage1/mbr.bin stage2/mboot.bin
dd if=/dev/zero of=./zeroes bs=512 count=1
cat stage1/mbr.bin zeroes stage2/mboot.bin >mbootblk
 
stage1/mbr.bin:
$(MAKE) -C stage1
 
stage2/mboot.bin:
$(MAKE) -C stage2
 
clean:
$(MAKE) -C stage1 clean
$(MAKE) -C stage2 clean
rm -f *~ zeroes mbootblk
/disk/tools/README
0,0 → 1,22
 
Tools
-----
 
mkdisk: make an empty disk image file
Usage: mkdisk <file name> <n>[M]
<n>: decimal number of sectors
if 'M' appended: megabytes instead of sectors
(sector size is always 512 bytes)
 
mkmboot: make a master boot block
There is no executable file made by this tool.
 
mkpart: make partitions on a disk
Usage: mkpart <disk image file> <configuration file>
 
shpart: show partitions on a disk
Usage: shpart <disk image file>
 
mkdata: make a set of test data files
There is no executable file made by this tool.
 
/disk/tools/Makefile
0,0 → 1,27
#
# Makefile for basic disk tools
#
 
BUILD = ../../build
 
DIRS = mkdisk mkmboot mkpart shpart mkdata fs-EOS32 fs-NetBSD
 
.PHONY: all install clean
 
all:
for i in $(DIRS) ; do \
$(MAKE) -C $$i all ; \
done
 
install:
for i in $(DIRS) ; do \
$(MAKE) -C $$i install ; \
done
mkdir -p $(BUILD)/run
cp Makefile.run $(BUILD)/run/Makefile
 
clean:
for i in $(DIRS) ; do \
$(MAKE) -C $$i clean ; \
done
rm -f *~
/disk/tools/mkpart/disk.part
0,0 → 1,47
#
# disk.part -- disk partitioning file
#
 
# The first line of this file (apart from empty or comment
# lines) must be the file name of the master boot block (or
# the string -noboot- if the disk need not be bootable).
 
./mbootblk
 
# The rest of this file consists of partition table entries,
# one per line. Each entry is in the following form:
#
# partition boot type start last description
#
# partition:
# possible values 0..15
# indicates partition number
# different entries need not be sorted in any way
# no two entries may have the same partition number
# boot:
# '*' means that the partition can be booted
# leave this blank if the partition cannot be booted
# more than one partition may be bootable
# type:
# possible values 0..0x7FFFFFFF
# indicates partition type
# 0x0000 = partition table entry not used
# 0x0058 = EOS32 file system partition
# 0x0059 = EOS32 swap space partition
# 0x00A9 = NetBSD partition
# start:
# sector number where partition starts (0-based)
# no partition may start below sector 32
# last:
# last sector of partition (0-based)
# partitions must not overlap
# description:
# max. 512 / 16 - 12 = 20 characters (includes trailing 0)
# this may be displayed during bootstrap
#
# The following example exactly fits on a 100M disk:
 
0 * 0x0058 32 17919 "EOS32 root"
1 0x0059 17920 33919 "EOS32 swap"
2 0x0058 33920 81919 "EOS32 usr"
3 * 0x00A9 81920 204799 "NetBSD 6.0"
/disk/tools/mkpart/mkpart.c
0,0 → 1,360
/*
* mkpart.c -- make partitions on a disk
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
 
 
#define SECTOR_SIZE 512
#define NPE (SECTOR_SIZE / sizeof(PartEntry))
#define DESCR_SIZE 20
 
#define LINE_SIZE 100
 
 
unsigned char buf[32 * SECTOR_SIZE];
 
 
typedef struct {
unsigned long type;
unsigned long start;
unsigned long size;
char descr[DESCR_SIZE];
} PartEntry;
 
PartEntry ptr[NPE];
 
 
/**************************************************************/
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
printf("Error: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
exit(1);
}
 
 
/**************************************************************/
 
 
void convertNumber(unsigned char *p, unsigned long val) {
*(p + 0) = val >> 24;
*(p + 1) = val >> 16;
*(p + 2) = val >> 8;
*(p + 3) = val >> 0;
}
 
 
void convertPartitionTable(PartEntry *e, int n) {
int i;
unsigned char *p;
 
for (i = 0; i < n; i++) {
p = (unsigned char *) &e[i];
convertNumber(p + 0, e[i].type);
convertNumber(p + 4, e[i].start);
convertNumber(p + 8, e[i].size);
}
}
 
 
/**************************************************************/
 
 
int parseNumber(char **pc, unsigned long *pi) {
char *p;
unsigned int base, dval;
unsigned long n;
 
p = *pc;
while (*p == ' ' || *p == '\t') {
p++;
}
if (*p == '\0' || *p == '\n') {
printf("Error: number is missing!\n");
return 0;
}
base = 10;
if (*p == '0') {
p++;
if (*p != '\0' && *p != '\n') {
if (*p == 'x' || *p == 'X') {
base = 16;
p++;
} else {
base = 8;
}
}
}
n = 0;
while ((*p >= '0' && *p <= '9') ||
(*p >= 'a' && *p <= 'f') ||
(*p >= 'A' && *p <= 'F')) {
if (*p >= '0' && *p <= '9') {
dval = (*p - '0');
} else
if (*p >= 'a' && *p <= 'f') {
dval = (*p - 'a' + 10);
} else
if (*p >= 'A' && *p <= 'F') {
dval = (*p - 'A' + 10);
}
if (dval >= base) {
printf("Error: digit value %d is illegal in number base %d\n",
dval, base);
return 0;
}
n *= base;
n += dval;
p++;
}
while (*p == ' ' || *p == '\t') {
p++;
}
*pc = p;
*pi = n;
return 1;
}
 
 
int parseString(char **pc, char *dst) {
char *p;
 
p = *pc;
while (*p == ' ' || *p == '\t') {
p++;
}
if (*p != '\"') {
return 0;
}
p++;
while (*p != '\"' && *p != '\0' && *p != '\n') {
*dst++ = *p++;
}
if (*p != '\"') {
return 0;
}
p++;
while (*p == ' ' || *p == '\t') {
p++;
}
*pc = p;
*dst = '\0';
return 1;
}
 
 
/**************************************************************/
 
 
int main(int argc, char *argv[]) {
char *diskName;
char *confName;
FILE *disk;
FILE *conf;
unsigned long diskSize;
unsigned long numSectors;
char line[LINE_SIZE];
char *p, *q;
int lineNumber;
FILE *mbootblk;
long mbootblkSize;
int i;
unsigned long partNum;
unsigned long bootable;
unsigned long partType;
unsigned long partStart;
unsigned long partLast;
unsigned long partSize;
char descr[LINE_SIZE];
 
/* check command line arguments */
if (argc != 3) {
printf("Usage: %s <disk image file> <configuration file>\n", argv[0]);
exit(1);
}
diskName = argv[1];
confName = argv[2];
/* determine disk size */
disk = fopen(diskName, "rb");
if (disk == NULL) {
error("cannot open disk image '%s'", diskName);
}
fseek(disk, 0, SEEK_END);
diskSize = ftell(disk);
numSectors = diskSize / SECTOR_SIZE;
fclose(disk);
printf("Disk '%s' has %lu (0x%lX) sectors.\n",
diskName, numSectors, numSectors);
if (numSectors < 32) {
error("disk is too small");
}
if (diskSize % SECTOR_SIZE != 0) {
printf("Warning: disk size is not a multiple of sector size!\n");
}
/* create partition table */
conf = fopen(confName, "rt");
if (conf == NULL) {
error("cannot open configuration file '%s'", confName);
}
lineNumber = 0;
/* first, handle master boot block specification */
while (fgets(line, LINE_SIZE, conf) != NULL) {
lineNumber++;
p = line;
while (*p == ' ' || *p == '\t') {
p++;
}
if (*p == '\0' || *p == '\n' || *p == '#') {
continue;
}
q = p;
while (*q > 0x20 && *q < 0x7F) {
q++;
}
*q = '\0';
if (strcmp(p, "-noboot-") == 0) {
/* master boot block not wanted */
} else {
/* p points to name of master boot block file */
mbootblk = fopen(p, "rb");
if (mbootblk == NULL) {
error("cannot open master boot block file '%s'", p);
}
fseek(mbootblk, 0, SEEK_END);
mbootblkSize = ftell(mbootblk);
fseek(mbootblk, 0, SEEK_SET);
if (mbootblkSize > 32 * SECTOR_SIZE) {
error("master boot block file '%s' is bigger than 32 sectors", p);
}
for (i = 0; i < 32 * SECTOR_SIZE; i++) {
buf[i] = '\0';
}
if (fread(buf, 1, mbootblkSize, mbootblk) != mbootblkSize) {
error("cannot read master boot block file '%s'", p);
}
fclose(mbootblk);
disk = fopen(diskName, "r+b");
if (disk == NULL) {
error("cannot open disk image '%s'", diskName);
}
if (fwrite(buf, 1, 32 * SECTOR_SIZE, disk) != 32 * SECTOR_SIZE) {
error("cannot write master boot block to disk image '%s'", diskName);
}
fclose(disk);
}
break;
}
/* then, handle partition table entries */
while (fgets(line, LINE_SIZE, conf) != NULL) {
lineNumber++;
p = line;
while (*p == ' ' || *p == '\t') {
p++;
}
if (*p == '\0' || *p == '\n' || *p == '#') {
continue;
}
if (!parseNumber(&p, &partNum)) {
error("cannot read partition number in config file '%s', line %d",
confName, lineNumber);
}
if (partNum >= 16) {
error("illegal partition number in config file '%s', line %d",
confName, lineNumber);
}
if (*p == '*') {
p++;
bootable = 0x80000000;
} else {
bootable = 0x00000000;
}
if (!parseNumber(&p, &partType)) {
error("cannot read partition type in config file '%s', line %d",
confName, lineNumber);
}
if ((partType & 0x80000000) != 0) {
error("illegal partition type in config file '%s', line %d",
confName, lineNumber);
}
if (!parseNumber(&p, &partStart)) {
error("cannot read start sector in config file '%s', line %d",
confName, lineNumber);
}
if (partStart < 32 || partStart >= numSectors) {
error("illegal start sector in config file '%s', line %d",
confName, lineNumber);
}
if (!parseNumber(&p, &partLast)) {
error("cannot read last sector in config file '%s', line %d",
confName, lineNumber);
}
if (partLast < partStart || partLast >= numSectors) {
error("illegal last sector in config file '%s', line %d",
confName, lineNumber);
}
partSize = partLast - partStart + 1;
if (!parseString(&p, descr)) {
error("cannot read description in config file '%s', line %d",
confName, lineNumber);
}
if (strlen(descr) >= DESCR_SIZE) {
error("description too long in config file '%s', line %d",
confName, lineNumber);
}
if (partType != 0) {
ptr[partNum].type = bootable | partType;
ptr[partNum].start = partStart;
ptr[partNum].size = partSize;
memset(ptr[partNum].descr, 0, DESCR_SIZE);
strcpy(ptr[partNum].descr, descr);
} else {
ptr[partNum].type = 0;
ptr[partNum].start = 0;
ptr[partNum].size = 0;
memset(ptr[partNum].descr, 0, DESCR_SIZE);
}
}
fclose(conf);
/* next, show partition table */
printf("Partitions:\n");
printf(" # b type start last size description\n");
for (partNum = 0; partNum < NPE; partNum++) {
if (ptr[partNum].type != 0) {
partLast = ptr[partNum].start + ptr[partNum].size - 1;
} else {
partLast = 0;
}
printf("%2lu %s 0x%08lX 0x%08lX 0x%08lX 0x%08lX %s\n",
partNum,
ptr[partNum].type & 0x80000000 ? "*" : " ",
ptr[partNum].type & 0x7FFFFFFF,
ptr[partNum].start,
partLast,
ptr[partNum].size,
ptr[partNum].descr);
}
/* finally, write partition table record */
convertPartitionTable(ptr, NPE);
disk = fopen(diskName, "r+b");
if (disk == NULL) {
error("cannot open disk image '%s'", diskName);
}
fseek(disk, 1 * SECTOR_SIZE, SEEK_SET);
if (fwrite(ptr, 1, SECTOR_SIZE, disk) != SECTOR_SIZE) {
error("cannot write partition table to disk image '%s'", diskName);
}
fclose(disk);
/* done */
return 0;
}
/disk/tools/mkpart/Makefile
0,0 → 1,38
#
# Makefile for mkpart utility
#
 
BUILD = ../../../build
 
CC = gcc -m32
CFLAGS = -g -Wall
LDFLAGS = -g
LDLIBS = -lm
 
SRCS = mkpart.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
BIN = mkpart
 
.PHONY: all install clean
 
all: $(BIN)
 
install: $(BIN)
mkdir -p $(BUILD)/bin
cp $(BIN) $(BUILD)/bin
mkdir -p $(BUILD)/run
cp disk.part $(BUILD)/run
 
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS)
 
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
 
depend.mak:
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak
 
-include depend.mak
 
clean:
rm -f *~ $(OBJS) $(BIN) depend.mak
/disk/server/diskserv.c
0,0 → 1,310
/*
* diskserv.c -- serial line disk server
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
 
 
#define SERIAL_PORT "/dev/tty01"
 
#define SYN 0x16
#define ACK 0x06
 
#define RESULT_OK 0x00
#define RESULT_UNCMD 0x01
#define RESULT_TOOBIG 0x02
#define RESULT_POSERR 0x03
#define RESULT_RDERR 0x04
#define RESULT_WRERR 0x05
 
 
static int debugCmds = 1;
static int debugData = 0;
 
static FILE *diskFile = NULL;
static unsigned int numSectors;
static int sfd = 0;
static struct termios origOptions;
static struct termios currOptions;
 
 
void serialClose(void);
 
 
void error(char *fmt, ...) {
va_list ap;
 
va_start(ap, fmt);
printf("Error: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
if (diskFile != NULL) {
fclose(diskFile);
diskFile = NULL;
}
if (sfd != 0) {
serialClose();
sfd = 0;
}
exit(1);
}
 
 
void serialOpen(void) {
sfd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
if (sfd == -1) {
error("cannot open serial port '%s'", SERIAL_PORT);
}
tcgetattr(sfd, &origOptions);
currOptions = origOptions;
cfsetispeed(&currOptions, B38400);
cfsetospeed(&currOptions, B38400);
currOptions.c_cflag |= (CLOCAL | CREAD);
currOptions.c_cflag &= ~PARENB;
currOptions.c_cflag &= ~CSTOPB;
currOptions.c_cflag &= ~CSIZE;
currOptions.c_cflag |= CS8;
currOptions.c_cflag &= ~CRTSCTS;
currOptions.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG | IEXTEN);
currOptions.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK);
currOptions.c_iflag &= ~(INPCK | ISTRIP | INLCR | IGNCR | ICRNL);
currOptions.c_iflag &= ~(IXON | IXOFF | IXANY);
currOptions.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
tcsetattr(sfd, TCSANOW, &currOptions);
}
 
 
void serialClose(void) {
tcsetattr(sfd, TCSANOW, &origOptions);
close(sfd);
}
 
 
int serialSnd(unsigned char b) {
int n;
 
n = write(sfd, &b, 1);
return n == 1;
}
 
 
int serialRcv(unsigned char *bp) {
int n;
 
n = read(sfd, bp, 1);
return n == 1;
}
 
 
void connect(void) {
unsigned char b;
 
printf("SYN... ");
fflush(stdout);
while (!serialSnd(ACK)) ;
tcdrain(sfd);
printf("ACK... ");
fflush(stdout);
while (!serialRcv(&b)) ;
if (b != ACK) {
error("cannot synchronize with client");
}
printf("connected\n");
}
 
 
void sendResult(unsigned char result) {
while (!serialSnd(result)) ;
tcdrain(sfd);
}
 
 
void showData(unsigned char buffer[512]) {
int i, j;
unsigned char c;
 
for (i = 0; i < 32; i++) {
printf("%03X ", i * 16);
for (j = 0; j < 16; j++) {
c = buffer[i * 16 + j];
printf("%02X ", c);
}
printf(" ");
for (j = 0; j < 16; j++) {
c = buffer[i * 16 + j];
if (c >= 0x20 && c < 0x7F) {
printf("%c", c);
} else {
printf(".");
}
}
printf("\n");
}
}
 
 
int main(int argc, char *argv[]) {
char *diskName;
int i;
unsigned char b;
unsigned char cmd;
unsigned int sector;
unsigned char buffer[512];
 
if (argc != 2) {
printf("Usage: %s <disk image file>\n", argv[0]);
exit(1);
}
diskName = argv[1];
diskFile = fopen(diskName, "r+b");
if (diskFile == NULL) {
error("cannot open disk image file '%s'", diskName);
}
fseek(diskFile, 0, SEEK_END);
numSectors = ftell(diskFile) / 512;
fseek(diskFile, 0, SEEK_SET);
printf("Disk '%s' has 0x%08X sectors.\n", diskName, numSectors);
/* open serial interface */
serialOpen();
/* wait for client to connect */
printf("Waiting for client...\n");
while (1) {
if (serialRcv(&b) && b == SYN) {
break;
}
}
connect();
/* connected, now handle requests */
while (1) {
while (!serialRcv(&cmd)) ;
if (cmd == 'q') {
/* for tests only, a real client would never quit */
if (debugCmds) {
printf("quit\n");
}
break;
}
if (cmd == SYN) {
/* this happens if the client has been reset */
connect();
continue;
}
if (cmd == 'c') {
/* client asks for disk capacity */
sendResult(RESULT_OK);
for (i = 0; i < 4; i++) {
b = (numSectors >> (8 * (3 - i))) & 0xFF;
while (!serialSnd(b)) ;
}
tcdrain(sfd);
if (debugCmds) {
printf("capacity... OK\n");
}
continue;
}
if (cmd != 'r' && cmd != 'w') {
/* unknown command */
sendResult(RESULT_UNCMD);
if (debugCmds) {
printf("unknown... UNCMD\n");
}
continue;
}
/* only read and write requests get here */
sector = 0;
for (i = 0; i < 4; i++) {
while (!serialRcv(&b)) ;
sector = (sector << 8) | b;
}
if (cmd == 'r') {
if (debugCmds) {
printf("reading sector 0x%08X... ", sector);
fflush(stdout);
}
if (sector >= numSectors) {
sendResult(RESULT_TOOBIG);
if (debugCmds) {
printf("TOOBIG\n");
}
} else
if (fseek(diskFile, sector * 512, SEEK_SET) != 0) {
sendResult(RESULT_POSERR);
if (debugCmds) {
printf("POSERR\n");
}
} else
if (fread(buffer, 1, 512, diskFile) != 512) {
sendResult(RESULT_RDERR);
if (debugCmds) {
printf("RDERR\n");
}
} else {
sendResult(RESULT_OK);
for (i = 0; i < 512; i++) {
while (!serialSnd(buffer[i])) ;
}
tcdrain(sfd);
if (debugCmds) {
printf("OK\n");
}
if (debugData) {
showData(buffer);
}
}
continue;
}
if (cmd == 'w') {
if (debugCmds) {
printf("writing sector 0x%08X... ", sector);
fflush(stdout);
}
for (i = 0; i < 512; i++) {
while (!serialRcv(buffer + i)) ;
}
if (sector >= numSectors) {
sendResult(RESULT_TOOBIG);
if (debugCmds) {
printf("TOOBIG\n");
}
} else
if (fseek(diskFile, sector * 512, SEEK_SET) != 0) {
sendResult(RESULT_POSERR);
if (debugCmds) {
printf("POSERR\n");
}
} else
if (fwrite(buffer, 1, 512, diskFile) != 512) {
sendResult(RESULT_WRERR);
if (debugCmds) {
printf("WRERR\n");
}
} else {
sendResult(RESULT_OK);
if (debugCmds) {
printf("OK\n");
}
if (debugData) {
showData(buffer);
}
}
continue;
}
}
if (diskFile != NULL) {
fclose(diskFile);
diskFile = NULL;
}
if (sfd != 0) {
serialClose();
sfd = 0;
}
return 0;
}
/disk/server/Makefile
0,0 → 1,19
#
# Makefile for serial line disk server
#
 
BUILD = ../../build
 
.PHONY: all install clean
 
all: diskserv
 
install: diskserv
mkdir -p $(BUILD)/bin
cp diskserv $(BUILD)/bin
 
diskserv: diskserv.c
gcc -m32 -g -Wall -o diskserv diskserv.c
 
clean:
rm -f *~ diskserv
/disk/Makefile
0,0 → 1,25
#
# Makefile for serial line disk server and basic disk tools
#
 
BUILD = ../build
 
DIRS = server tools
 
.PHONY: all install clean
 
all:
for i in $(DIRS) ; do \
$(MAKE) -C $$i all ; \
done
 
install:
for i in $(DIRS) ; do \
$(MAKE) -C $$i install ; \
done
 
clean:
for i in $(DIRS) ; do \
$(MAKE) -C $$i clean ; \
done
rm -f *~
/Makefile
4,7 → 4,7
 
VERSION = 0.22
 
DIRS = doc binutils sim simtest fpga hwtests monitor
DIRS = doc binutils sim simtest fpga hwtests monitor disk
BUILD = `pwd`/build
 
.PHONY: all compiler builddir clean dist

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.