URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/tags/eco32-0.22/disk/tools/fs-NetBSD
- from Rev 17 to Rev 21
- ↔ Reverse comparison
Rev 17 → Rev 21
/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 |
/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_ */ |
/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_ */ |
/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; |
} |
/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_ */ |
/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_ */ |
/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_ */ |
/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). |
|
/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_ */ |
/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 |
/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: |
/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: |
/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_ */ |
/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); |
} |
/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_ */ |
/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_ */ |
/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 |
/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; |
} |
/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_ */ |
/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); |
} |
/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); |
} |
/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_ */ |
/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 *); |
/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, |
}; |
/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 |
} |
/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]); |
} |
} |
/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 */ |
/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); |
} |
/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 |
/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 |
/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_ */ |
/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); |
} |
/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) |
/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_ */ |
/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 */ |
/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 */ |
/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_ */ |
/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); |
} |
/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); |
} |
/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 |
/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); |
} |
/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_ */ |
/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_ */ |
/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_ */ |
/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; |
} |
/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 |
/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 |
/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 |
/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_ */ |
/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 |
/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: |
/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; |
} |
/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: |
/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_ */ |
/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_ */ |
/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_ */ |
/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_ */ |
/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_ */ |
/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 |
/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_ */ |
/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 |
/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 |
/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; |
} |
/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 *~ |