home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * 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();
- }
-