home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume8
/
packdisk
/
packdisk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-08
|
11KB
|
487 lines
/*
*
* This program takes a disk and makes all the files and directories,
* and the free list, contiguous.
*
* Andrew Fyfe
* 7 October 1989
*
* andy@csvax.caltech.edu
*/
#include <sys/filsys.h>
#include <sys/ino.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_ADDR 13
#define FIRST_INDIR 10 /* 0-9 direct, 10 single, 11 double, 12 triple */
#define NUM_INDIR (NUM_ADDR - FIRST_INDIR)
char *cmd_name;
int disk, dev;
struct filsys filsys;
struct dinode ino; /* current working inode, and its number */
ino_t w_ino;
char *inode_block; /* block containing last read/written inode */
daddr_t w_ino_blk; /* and its number */
char *indir[NUM_INDIR]; /* current working indirect blocks */
daddr_t w_indir[NUM_INDIR]; /* and their numbers */
daddr_t next_fill; /* next (sequential) block to fill */
char *inode_table; /* a cache of the entire inode section of the disk */
long *map; /* a map from block numbers to referencing inode/indir block */
static void read_superblk(void);
static void write_superblk(void);
static void map_inode(ino_t inode);
static void update_map(long map_entry, daddr_t block, int level);
static void read_block(daddr_t block, void *buf);
static void write_block(daddr_t block, void *buf);
static void read_inode(ino_t inode, struct dinode *buf);
static void write_inode(ino_t inode, struct dinode *buf);
static void move_block(daddr_t from, daddr_t to);
static void move_inode(ino_t inode);
static void move_indirect(daddr_t block, int level);
static void make_hole(void);
static void rebuild_free_list(void);
extern void l3tol(long *, char *, int length);
extern void ltol3(char *, long *, int length);
void
main(int argc, char *argv[])
{
ino_t inode, total_inodes;
daddr_t block;
int i;
char *ctime(long *);
#ifndef DEBUG
struct stat statb;
extern int stat(const char *, struct stat *);
#endif
cmd_name = argv[0];
if (argc != 2) {
fprintf(stderr, "%s: Usage: %s <file system>\n",
cmd_name, cmd_name);
exit(1);
}
#ifndef DEBUG
if (stat(argv[1], &statb) < 0) {
fprintf(stderr, "%s: can't stat %s: ", cmd_name, argv[1]);
perror("");
exit(1);
}
if ((statb.st_mode & S_IFMT) != S_IFCHR) {
fprintf(stderr, "%s: %s is not a character device\n",
cmd_name, argv[1]);
exit(1);
}
#endif
disk = open(argv[1], 2, 0);
if (disk < 0) {
fprintf(stderr, "%s: can't open %s: ", cmd_name, argv[1]);
perror("");
exit(1);
}
read_superblk();
total_inodes = (filsys.s_isize - FsITOD(dev, ROOTINO)) * FsINOPB(dev);
fprintf(stderr, "File system: name: \"%.6s\", pack: \"%.6s\"\n",
filsys.s_fname, filsys.s_fpack);
fprintf(stderr, "\tlast modified on %s", ctime(&filsys.s_time));
fprintf(stderr,
"\ttotal inodes = %d, data blocks = %d, total = %d blocks\n",
total_inodes, filsys.s_fsize - filsys.s_isize, filsys.s_fsize);
fprintf(stderr, "\tfree blocks = %d, free inodes = %d\n",
filsys.s_tfree, filsys.s_tinode);
for (i = 0; i < NUM_INDIR; ++i) {
w_indir[i] = 0;
indir[i] = malloc(FsBSIZE(dev));
if (indir[i] == 0) {
fprintf(stderr, "%s: can't malloc indir buffer space: ", cmd_name);
perror("");
exit(1);
}
}
w_ino = 0;
map = calloc(filsys.s_fsize, sizeof(*map));
if (map == 0) {
fprintf(stderr, "%s: can't calloc map: ", cmd_name);
perror("");
exit(1);
}
inode_table = malloc(filsys.s_isize * FsBSIZE(dev));
if (inode_table == 0) {
fprintf(stderr, "%s: can't malloc space for inode table\n", cmd_name);
w_ino_blk = 0;
inode_block = malloc(FsBSIZE(dev));
if (inode_block == 0) {
fprintf(stderr, "%s: can't malloc inode buffer space: ", cmd_name);
perror("");
exit(1);
}
}
else
for (block = FsITOD(dev, ROOTINO); block < filsys.s_isize; ++block)
read_block(block, &inode_table[block * FsBSIZE(dev)]);
fprintf(stderr, "mapping...");
for (inode = ROOTINO; inode <= total_inodes; ++inode)
map_inode(inode);
fprintf(stderr, "done\n");
next_fill = filsys.s_isize;
for (inode = ROOTINO; inode <= total_inodes; ++inode)
move_inode(inode);
fprintf(stderr, "\nrebuilding the free list\n");
rebuild_free_list();
fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
close(disk);
exit(0);
}
static void
read_superblk(void)
{
if (lseek(disk, SUPERBOFF, 0) != SUPERBOFF) {
fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
perror("");
exit(1);
}
if (read(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
fprintf(stderr, "%s: can't read superblock: ", cmd_name);
perror("");
exit(1);
}
if (filsys.s_magic != FsMAGIC) {
fprintf(stderr, "%s: invalid superblock magic number\n", cmd_name);
exit(1);
}
dev = (filsys.s_type == Fs2b) ? Fs2BLK : 0;
}
static void
write_superblk(void)
{
lseek(disk, SUPERBOFF, 0);
if (write(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
fprintf(stderr, "%s: can't write superblock: ", cmd_name);
perror("");
exit(1);
}
}
static void
map_inode(ino_t inode)
{
int type, i;
long block[NUM_ADDR];
read_inode(inode, &ino);
if (ino.di_mode == 0)
return;
type = ino.di_mode & S_IFMT;
if (type == S_IFCHR || type == S_IFBLK)
return;
l3tol(block, ino.di_addr, NUM_ADDR);
for (i = 0; i < NUM_ADDR; ++i)
if (block[i] != 0)
update_map(inode, block[i],
(i < FIRST_INDIR) ? 0 : (i - FIRST_INDIR + 1));
}
static void
update_map(long map_entry, daddr_t block, int level)
{
int i;
if (map[block] != 0) {
fprintf(stderr, "%s: duplicate block %d in %d and %d\n",
cmd_name, block, map[block], map_entry);
exit(1);
}
map[block] = map_entry;
if (level == 0)
return;
--level;
read_block(block, indir[level]);
for (i = 0; i < FsNINDIR(dev); ++i)
if (((daddr_t *)indir[level])[i] != 0)
update_map(-block, ((daddr_t *)indir[level])[i], level);
}
static void
read_block(daddr_t block, void *buf)
{
lseek(disk, block * FsBSIZE(dev), 0);
if (read(disk, buf, FsBSIZE(dev)) != FsBSIZE(dev)) {
fprintf(stderr, "%s: can't read block %d: ", cmd_name, block);
perror("");
exit(1);
}
}
static void
write_block(daddr_t block, void *buf)
{
lseek(disk, block * FsBSIZE(dev), 0);
if (write(disk, buf, FsBSIZE(dev)) != FsBSIZE(dev)) {
fprintf(stderr, "%s: can't write block %d: ", cmd_name, block);
perror("");
exit(1);
}
}
static void
read_inode(ino_t inode, struct dinode *ino)
{
daddr_t block;
block = FsITOD(dev, inode);
if (inode_table == 0) {
if (w_ino_blk != block) {
w_ino_blk = block;
read_block(block, inode_block);
}
*ino = ((struct dinode *)inode_block)[FsITOO(dev, inode)];
}
else {
*ino = ((struct dinode *)&inode_table[block * FsBSIZE(dev)])
[FsITOO(dev, inode)];
}
}
static void
write_inode(ino_t inode, struct dinode *ino)
{
daddr_t block;
block = FsITOD(dev, inode);
if (inode_table == 0) {
if (w_ino_blk != block) {
w_ino_blk = block;
read_block(block, inode_block);
}
((struct dinode *)inode_block)[FsITOO(dev, inode)] = *ino;
write_block(block, inode_block);
}
else {
((struct dinode *)&inode_table[block * FsBSIZE(dev)])
[FsITOO(dev, inode)] = *ino;
write_block(block, &inode_table[block * FsBSIZE(dev)]);
}
}
static void
move_block(daddr_t from, daddr_t to)
{
char buffer[FsBSIZE(dev)];
daddr_t block;
if (map[to] != 0)
make_hole();
read_block(from, buffer);
write_block(to, buffer);
map[to] = map[from];
map[from] = 0;
for (block = filsys.s_isize; block < filsys.s_fsize; ++block)
if (map[block] == -from)
map[block] = -to;
}
static void
move_inode(ino_t inode)
{
int type, i;
long block[NUM_ADDR];
read_inode(inode, &ino);
w_ino = inode;
if (ino.di_mode == 0)
return;
type = ino.di_mode & S_IFMT;
if (type == S_IFCHR || type == S_IFBLK)
return;
fprintf(stderr, "moving inode %d (size %d) \r",
inode, ino.di_size);
l3tol(block, ino.di_addr, NUM_ADDR);
for (i = 0; i < NUM_ADDR; ++i) {
if (block[i] == 0)
continue;
if (block[i] != next_fill) {
move_block(block[i], next_fill);
l3tol(block, ino.di_addr, NUM_ADDR);
block[i] = next_fill;
ltol3(ino.di_addr, block, NUM_ADDR);
write_inode(inode, &ino);
}
++next_fill;
}
for (i = FIRST_INDIR; i < NUM_ADDR; ++i)
move_indirect(block[i], i-FIRST_INDIR);
}
static void
move_indirect(daddr_t block, int level)
{
int i;
if (block == 0)
return;
read_block(block, indir[level]);
w_indir[level] = block;
for (i = 0; i < FsNINDIR(dev); ++i) {
if (((daddr_t *)indir[level])[i] == 0)
continue;
if (((daddr_t *)indir[level])[i] != next_fill) {
move_block(((daddr_t *)indir[level])[i], next_fill);
((daddr_t *)indir[level])[i] = next_fill;
write_block(block, indir[level]);
}
++next_fill;
}
if (level == 0)
return;
for (i = 0; i < FsNINDIR(dev); ++i)
move_indirect(((daddr_t *)indir[level])[i], level-1);
}
static void
make_hole(void)
{
char t_indir[FsBSIZE(dev)];
daddr_t *p_indir;
struct dinode t_ino, *p_ino;
long block[NUM_ADDR];
daddr_t back;
int i;
back = filsys.s_fsize - 1;
while (next_fill < back && map[back] != 0)
--back;
if (next_fill >= back) {
fprintf(stderr, "%s: can't find a free block for %d\n",
cmd_name, next_fill);
exit(1);
}
move_block(next_fill, back);
if (map[back] < 0) {
block[0] = -map[back];
for (i = 0; i < NUM_INDIR; ++i)
if (block[0] == w_indir[i])
break;
if (i < NUM_INDIR) {
p_indir = (daddr_t *)indir[i];
}
else {
p_indir = (daddr_t *)t_indir;
read_block(block[0], t_indir);
}
for (i = 0; i < FsNINDIR(dev); ++i) {
if (p_indir[i] == next_fill) {
p_indir[i] = back;
break;
}
}
if (i == FsNINDIR(dev)) {
fprintf(stderr,
"%s: panic: can't find %d in indirect block %d\n",
cmd_name, next_fill, -map[back]);
exit(1);
}
write_block(block[0], p_indir);
}
else {
if (map[back] == w_ino) {
p_ino = &ino;
}
else {
p_ino = &t_ino;
read_inode(map[back], &t_ino);
}
l3tol(block, p_ino->di_addr, NUM_ADDR);
for (i = 0; i < NUM_ADDR; ++i) {
if (block[i] == next_fill) {
block[i] = back;
ltol3(p_ino->di_addr, block, NUM_ADDR);
break;
}
}
if (i == NUM_ADDR) {
fprintf(stderr, "%s: panic: can't find %d in inode %d\n",
cmd_name, next_fill, map[back]);
exit(1);
}
write_inode(map[back], p_ino);
}
}
static void
rebuild_free_list(void)
{
int free_size, nfree;
daddr_t free[NICFREE], block;
char buf[FsBSIZE(dev)];
free_size = filsys.s_fsize - next_fill;
if (free_size != filsys.s_tfree) {
fprintf(stderr, "%s: free list changed size from %d to %d\n",
cmd_name, filsys.s_tfree, free_size);
exit(1);
}
nfree = 1;
memset(free, 0, sizeof(free));
memset(buf, 0, sizeof(buf));
for (block = filsys.s_fsize - 1; block >= next_fill; --block) {
if (nfree == NICFREE) {
((daddr_t *)buf)[0] = nfree;
memcpy(&((daddr_t *)buf)[1], free, sizeof(free));
write_block(block, buf);
nfree = 0;
memset(free, 0, sizeof(free));
}
free[nfree++] = block;
}
filsys.s_nfree = nfree;
memcpy(&filsys.s_free, free, sizeof(free));
write_superblk();
}