[comp.sources.d] v08i093: System V disk compactor

george@rebel.UUCP (George M. Sipe) (10/12/89)

I've just tested Andy Fyfe's "packdisk" posted to comp.sources.misc,
volume 8, issue 93.  It's great!  Thanks Andy.

My system is a UniPlus System V.0 and packdisk worked without fault.
When done, fsck reported no problems.  Even sparse files (history DBM
stuff) were handle correctly (fsck bitches about that, always does).

Using Michael Young's "fsanalyze" before and after the "packing" of
a 20 MB partition produced the following output:

before>  File system name = "u", Volume name = "w00c"
before>  Logical block size = 1024 bytes
before>  Interleave = 1 sectors; 136 sectors/cyl
before>  Volume Size = 17272 blocks (17686528 bytes)
before>  	271 blocks reserved for super block and inodes (4304 inodes)
before>  	17001 blocks reserved for data
before>  38.50% inodes used (1657 used, 2647 free)
before>  78.08% data blocks used (13274 used, 3727 free)
before>  
before>  Fragmentation         = 37.70%           Special files    = 0 (0.00%)
before>  Average Seek Distance = 57.31 cyls       Indirect files   = 154 (9.29%)
before>  Rotation delays       = 4.22%            Double indirects = 7 (0.42%)
before>  Multiply-linked files = 181 (10.92%)     Triple indirects = 0 (0.00%)
before>  Directories           = 85 (5.13%)       Indirection blks = 172 (1.01%)
before>  Oversized directories = 0 (0.00%)        Sparse files     = 1 (0.06%)
before>  Unused bytes in last blocks = 961397 (5.44%)

after>   File system name = "u", Volume name = "w00c"
after>   Logical block size = 1024 bytes
after>   Interleave = 1 sectors; 136 sectors/cyl
after>   Volume Size = 17272 blocks (17686528 bytes)
after>   	271 blocks reserved for super block and inodes (4304 inodes)
after>   	17001 blocks reserved for data
after>   38.50% inodes used (1657 used, 2647 free)
after>   78.08% data blocks used (13274 used, 3727 free)
after>   
after>   Fragmentation         = 0.96%            Special files    = 0 (0.00%)
after>   Average Seek Distance = 1.60 cyls        Indirect files   = 154 (9.29%)
after>   Rotation delays       = 0.08%            Double indirects = 7 (0.42%)
after>   Multiply-linked files = 181 (10.92%)     Triple indirects = 0 (0.00%)
after>   Directories           = 85 (5.13%)       Indirection blks = 172 (1.01%)
after>   Oversized directories = 0 (0.00%)        Sparse files     = 1 (0.06%)
after>   Unused bytes in last blocks = 961397 (5.44%)

Quite an improvement.  "Feels" faster too.  On my aging 68K system, this took
about 3 hours to complete.  Packdisk showed it's progess (inode #) as it went.
Your mileage may vary...  be sure to backup everything before starting.

In his posting, Andy noted:
> Though this program was developed on a 3b1, it was written with
> portability in mind (yes, I know -- you can stop laughing now!).
> Perhaps other systems with the System V file system (inherited from
> V7?) can also use the program, or adapt it to their needs.

Well, it is very portable, except for using gcc as the implementation base.
Not to take away from gcc, it's just that some of us (me for instance) don't
have it up and are stuck with pcc for now.  That mean's, among other things
no function prototypes.

Slight hacking on the source to allow "OLDC" (#ifdef'ed) produced the following
patch file.  While I was at it, I also put a few casts in place to humor lint.
Again, works well for me... your mileage may vary.

Regards,

George M. Sipe,		       Phone: (404) 447-4731
537 Lakeshore Drive, Berkeley Lake, GA  30136-3035
UUCP: ...!{decvax,linus,rutgers}!gatech!rebel!george



*** opackdisk.c	Wed Oct 11 21:41:07 1989
--- packdisk.c	Wed Oct 11 21:42:50 1989
***************
*** 9,14
   *						andy@csvax.caltech.edu
   */
  
  #include <sys/filsys.h>
  #include <sys/ino.h>
  #include <sys/stat.h>

--- 9,19 -----
   *						andy@csvax.caltech.edu
   */
  
+ #ifndef	OLDC
+ #include <stdlib.h>
+ #endif
+ #include <sys/types.h>
+ #include <sys/param.h>
  #include <sys/filsys.h>
  #include <sys/ino.h>
  #include <sys/stat.h>
***************
*** 13,19
  #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 */

--- 18,23 -----
  #include <sys/ino.h>
  #include <sys/stat.h>
  #include <stdio.h>
  
  #ifndef	OLDC
  #define	FsBSIZEdev	FsBSIZE(dev)
***************
*** 15,20
  #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)

--- 19,30 -----
  #include <sys/stat.h>
  #include <stdio.h>
  
+ #ifndef	OLDC
+ #define	FsBSIZEdev	FsBSIZE(dev)
+ #else
+ #define	FsBSIZEdev	1024		/* BE SURE THIS IS OK FOR YOU */
+ #endif
+ 
  #define NUM_ADDR	13
  #define FIRST_INDIR	10   /* 0-9 direct, 10 single, 11 double, 12 triple */
  #define NUM_INDIR	(NUM_ADDR - FIRST_INDIR)
***************
*** 39,44
  
  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);

--- 49,55 -----
  
  long *map;	/* a map from block numbers to referencing inode/indir block */
  
+ #ifndef	OLDC
  static void read_superblk(void);
  static void write_superblk(void);
  static void map_inode(ino_t inode);
***************
*** 55,60
  
  extern void l3tol(long *, char *, int length);
  extern void ltol3(char *, long *, int length);
  
  void
  main(int argc, char *argv[])

--- 66,80 -----
  
  extern void l3tol(long *, char *, int length);
  extern void ltol3(char *, long *, int length);
+ #else
+ #define	move_indirect		Move_Indirect		/* make uniq */
+ extern char *calloc();
+ extern char *malloc();
+ extern char *memcpy();
+ extern char *memset();
+ extern long lseek();
+ extern void exit();
+ extern void perror();
  
  static void read_superblk();
  static void write_superblk();
***************
*** 56,63
  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;

--- 76,102 -----
  extern void exit();
  extern void perror();
  
! static void read_superblk();
! static void write_superblk();
! static void map_inode();
! static void update_map();
! static void read_block();
! static void write_block();
! static void read_inode();
! static void write_inode();
! static void move_block();
! static void move_inode();
! static void move_indirect();
! static void make_hole();
! static void rebuild_free_list();
! 
! extern void l3tol();
! extern void ltol3();
! #endif
! 
! int main(argc, argv)
! int argc;
! char *argv[];
  {
      ino_t inode, total_inodes;
      daddr_t block;
***************
*** 62,67
      ino_t inode, total_inodes;
      daddr_t block;
      int i;
      char *ctime(long *);
  #ifndef DEBUG
      struct stat statb;

--- 101,107 -----
      ino_t inode, total_inodes;
      daddr_t block;
      int i;
+ #ifndef	OLDC
      char *ctime(long *);
  #ifndef DEBUG
      struct stat statb;
***************
*** 67,72
      struct stat statb;
      extern int stat(const char *, struct stat *);
  #endif
  
      cmd_name = argv[0];
  

--- 107,119 -----
      struct stat statb;
      extern int stat(const char *, struct stat *);
  #endif
+ #else
+     char *ctime();
+ #ifndef DEBUG
+     struct stat statb;
+     extern int stat();
+ #endif
+ #endif
  
      cmd_name = argv[0];
  
***************
*** 71,77
      cmd_name = argv[0];
  
      if (argc != 2) {
! 	fprintf(stderr, "%s: Usage: %s <file system>\n",
  	    cmd_name, cmd_name);
  	exit(1);
      }

--- 118,124 -----
      cmd_name = argv[0];
  
      if (argc != 2) {
! 	(void) fprintf(stderr, "%s: Usage: %s <file system>\n",
  	    cmd_name, cmd_name);
  	exit(1);
      }
***************
*** 78,84
  
  #ifndef DEBUG
      if (stat(argv[1], &statb) < 0) {
! 	fprintf(stderr, "%s: can't stat %s: ", cmd_name, argv[1]);
  	perror("");
  	exit(1);
      }

--- 125,131 -----
  
  #ifndef DEBUG
      if (stat(argv[1], &statb) < 0) {
! 	(void) fprintf(stderr, "%s: can't stat %s: ", cmd_name, argv[1]);
  	perror("");
  	exit(1);
      }
***************
*** 83,89
  	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);
      }

--- 130,136 -----
  	exit(1);
      }
      if ((statb.st_mode & S_IFMT) != S_IFCHR) {
! 	(void) fprintf(stderr, "%s: %s is not a character device\n",
  	    cmd_name, argv[1]);
  	exit(1);
      }
***************
*** 91,97
  
      disk = open(argv[1], 2, 0);
      if (disk < 0) {
! 	fprintf(stderr, "%s: can't open %s: ", cmd_name, argv[1]);
  	perror("");
  	exit(1);
      }

--- 138,144 -----
  
      disk = open(argv[1], 2, 0);
      if (disk < 0) {
! 	(void) fprintf(stderr, "%s: can't open %s: ", cmd_name, argv[1]);
  	perror("");
  	exit(1);
      }
***************
*** 99,105
      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,

--- 146,152 -----
      read_superblk();
  
      total_inodes = (filsys.s_isize - FsITOD(dev, ROOTINO)) * FsINOPB(dev);
!     (void) fprintf(stderr, "File system: name: \"%.6s\", pack: \"%.6s\"\n",
  	filsys.s_fname, filsys.s_fpack);
      (void) fprintf(stderr, "\tlast modified on %s", ctime(&filsys.s_time));
      (void) fprintf(stderr,
***************
*** 101,108
      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",

--- 148,155 -----
      total_inodes = (filsys.s_isize - FsITOD(dev, ROOTINO)) * FsINOPB(dev);
      (void) fprintf(stderr, "File system: name: \"%.6s\", pack: \"%.6s\"\n",
  	filsys.s_fname, filsys.s_fpack);
!     (void) fprintf(stderr, "\tlast modified on %s", ctime(&filsys.s_time));
!     (void) fprintf(stderr,
  	"\ttotal inodes = %d, data blocks = %d, total = %d blocks\n",
  	total_inodes, filsys.s_fsize - filsys.s_isize, filsys.s_fsize);
      (void) fprintf(stderr, "\tfree blocks = %d, free inodes = %d\n",
***************
*** 105,111
      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) {

--- 152,158 -----
      (void) fprintf(stderr,
  	"\ttotal inodes = %d, data blocks = %d, total = %d blocks\n",
  	total_inodes, filsys.s_fsize - filsys.s_isize, filsys.s_fsize);
!     (void) fprintf(stderr, "\tfree blocks = %d, free inodes = %d\n",
  	filsys.s_tfree, filsys.s_tinode);
  
      for (i = 0; i < NUM_INDIR; ++i) {
***************
*** 110,116
  
      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("");

--- 157,163 -----
  
      for (i = 0; i < NUM_INDIR; ++i) {
  	w_indir[i] = 0;
! 	indir[i] = (char *) malloc((unsigned) FsBSIZE(dev));
  	if (indir[i] == 0) {
  	    (void) fprintf(stderr, "%s: can't malloc indir buffer space: ",
  		cmd_name);
***************
*** 112,118
  	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);
  	}

--- 159,166 -----
  	w_indir[i] = 0;
  	indir[i] = (char *) malloc((unsigned) FsBSIZE(dev));
  	if (indir[i] == 0) {
! 	    (void) fprintf(stderr, "%s: can't malloc indir buffer space: ",
! 		cmd_name);
  	    perror("");
  	    exit(1);
  	}
***************
*** 119,125
      }
      w_ino = 0;
  
!     map = calloc(filsys.s_fsize, sizeof(*map));
      if (map == 0) {
  	fprintf(stderr, "%s: can't calloc map: ", cmd_name);
  	perror("");

--- 167,173 -----
      }
      w_ino = 0;
  
!     map = (long *) calloc((unsigned) filsys.s_fsize, sizeof(*map));
      if (map == 0) {
  	(void) fprintf(stderr, "%s: can't calloc map: ", cmd_name);
  	perror("");
***************
*** 121,127
  
      map = calloc(filsys.s_fsize, sizeof(*map));
      if (map == 0) {
! 	fprintf(stderr, "%s: can't calloc map: ", cmd_name);
  	perror("");
  	exit(1);
      }

--- 169,175 -----
  
      map = (long *) calloc((unsigned) filsys.s_fsize, sizeof(*map));
      if (map == 0) {
! 	(void) fprintf(stderr, "%s: can't calloc map: ", cmd_name);
  	perror("");
  	exit(1);
      }
***************
*** 126,132
  	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;

--- 174,180 -----
  	exit(1);
      }
  
!     inode_table = (char *) malloc(filsys.s_isize * FsBSIZE(dev));
      if (inode_table == 0) {
  	(void) fprintf(stderr, "%s: can't malloc space for inode table\n",
  	    cmd_name);
***************
*** 128,134
  
      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) {

--- 176,183 -----
  
      inode_table = (char *) malloc(filsys.s_isize * FsBSIZE(dev));
      if (inode_table == 0) {
! 	(void) fprintf(stderr, "%s: can't malloc space for inode table\n",
! 	    cmd_name);
  	w_ino_blk = 0;
  	inode_block = (char *) malloc((unsigned) FsBSIZE(dev));
  	if (inode_block == 0) {
***************
*** 130,136
      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("");

--- 179,185 -----
  	(void) fprintf(stderr, "%s: can't malloc space for inode table\n",
  	    cmd_name);
  	w_ino_blk = 0;
! 	inode_block = (char *) malloc((unsigned) FsBSIZE(dev));
  	if (inode_block == 0) {
  	    (void) fprintf(stderr, "%s: can't malloc inode buffer space: ",
  		cmd_name);
***************
*** 132,138
  	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);
  	}

--- 181,188 -----
  	w_ino_blk = 0;
  	inode_block = (char *) malloc((unsigned) FsBSIZE(dev));
  	if (inode_block == 0) {
! 	    (void) fprintf(stderr, "%s: can't malloc inode buffer space: ",
! 		cmd_name);
  	    perror("");
  	    exit(1);
  	}
***************
*** 141,147
  	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");

--- 191,197 -----
  	for (block = FsITOD(dev, ROOTINO); block < filsys.s_isize; ++block)
  	    read_block(block, &inode_table[block * FsBSIZE(dev)]);
  
!     (void) fprintf(stderr, "mapping...");
      for (inode = ROOTINO; inode <= total_inodes; ++inode)
  	map_inode(inode);
      (void) fprintf(stderr, "done\n");
***************
*** 144,150
      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)

--- 194,200 -----
      (void) fprintf(stderr, "mapping...");
      for (inode = ROOTINO; inode <= total_inodes; ++inode)
  	map_inode(inode);
!     (void) fprintf(stderr, "done\n");
  
      next_fill = filsys.s_isize;
      for (inode = ROOTINO; inode <= total_inodes; ++inode)
***************
*** 150,156
      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");

--- 200,206 -----
      for (inode = ROOTINO; inode <= total_inodes; ++inode)
  	move_inode(inode);
  
!     (void) fprintf(stderr, "\nrebuilding the free list\n");
      rebuild_free_list();
  
      (void) fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
***************
*** 153,159
      fprintf(stderr, "\nrebuilding the free list\n");
      rebuild_free_list();
  
!     fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
  
      close(disk);
      exit(0);

--- 203,209 -----
      (void) fprintf(stderr, "\nrebuilding the free list\n");
      rebuild_free_list();
  
!     (void) fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
  
      (void) close(disk);
      exit(0);
***************
*** 155,161
  
      fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
  
!     close(disk);
      exit(0);
  }
  

--- 205,211 -----
  
      (void) fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
  
!     (void) close(disk);
      exit(0);
  }
  
***************
*** 159,166
      exit(0);
  }
  
! static void
! read_superblk(void)
  {
      if (lseek(disk, SUPERBOFF, 0) != SUPERBOFF) {
  	fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);

--- 209,215 -----
      exit(0);
  }
  
! static void read_superblk()
  {
      if (lseek(disk, SUPERBOFF, 0) != (long) SUPERBOFF) {
  	(void) fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
***************
*** 162,169
  static void
  read_superblk(void)
  {
!     if (lseek(disk, SUPERBOFF, 0) != SUPERBOFF) {
! 	fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
  	perror("");
  	exit(1);
      }

--- 211,218 -----
  
  static void read_superblk()
  {
!     if (lseek(disk, SUPERBOFF, 0) != (long) SUPERBOFF) {
! 	(void) fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
  	perror("");
  	exit(1);
      }
***************
*** 168,174
  	exit(1);
      }
      if (read(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
! 	fprintf(stderr, "%s: can't read superblock: ", cmd_name);
  	perror("");
  	exit(1);
      }

--- 217,223 -----
  	exit(1);
      }
      if (read(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
! 	(void) fprintf(stderr, "%s: can't read superblock: ", cmd_name);
  	perror("");
  	exit(1);
      }
***************
*** 173,179
  	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;

--- 222,229 -----
  	exit(1);
      }
      if (filsys.s_magic != FsMAGIC) {
! 	(void) fprintf(stderr, "%s: invalid superblock magic number\n",
! 	    cmd_name);
  	exit(1);
      }
      dev = (filsys.s_type == Fs2b) ? Fs2BLK : 0;
***************
*** 179,186
      dev = (filsys.s_type == Fs2b) ? Fs2BLK : 0;
  }
  
! static void
! write_superblk(void)
  {
      lseek(disk, SUPERBOFF, 0);
      if (write(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {

--- 229,235 -----
      dev = (filsys.s_type == Fs2b) ? Fs2BLK : 0;
  }
  
! static void write_superblk()
  {
      if (lseek(disk, SUPERBOFF, 0) == -1L
  	    || write(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
***************
*** 182,190
  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);
      }

--- 231,239 -----
  
  static void write_superblk()
  {
!     if (lseek(disk, SUPERBOFF, 0) == -1L
! 	    || write(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
! 	(void) fprintf(stderr, "%s: can't write superblock: ", cmd_name);
  	perror("");
  	exit(1);
      }
***************
*** 190,197
      }
  }
  
! static void
! map_inode(ino_t inode)
  {
      int type, i;
      long block[NUM_ADDR];

--- 239,246 -----
      }
  }
  
! static void map_inode(inode)
! ino_t inode;
  {
      int type, i;
      long block[NUM_ADDR];
***************
*** 206,212
      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));
  }
  

--- 255,261 -----
      l3tol(block, ino.di_addr, NUM_ADDR);
      for (i = 0; i < NUM_ADDR; ++i)
  	if (block[i] != 0)
! 	    update_map((long) inode, block[i],
  		(i < FIRST_INDIR) ? 0 : (i - FIRST_INDIR + 1));
  }
  
***************
*** 210,217
  		(i < FIRST_INDIR) ? 0 : (i - FIRST_INDIR + 1));
  }
  
! static void
! update_map(long map_entry, daddr_t block, int level)
  {
      int i;
  

--- 259,268 -----
  		(i < FIRST_INDIR) ? 0 : (i - FIRST_INDIR + 1));
  }
  
! static void update_map(map_entry, block, level)
! long map_entry;
! daddr_t block;
! int level;
  {
      int i;
  
***************
*** 216,222
      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);
      }

--- 267,273 -----
      int i;
  
      if (map[block] != 0) {
! 	(void) fprintf(stderr, "%s: duplicate block %d in %d and %d\n",
  	    cmd_name, block, map[block], map_entry);
  	exit(1);
      }
***************
*** 232,239
  	    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)) {

--- 283,291 -----
  	    update_map(-block, ((daddr_t *)indir[level])[i], level);
  }
  
! static void read_block(block, buf)
! daddr_t block;
! char *buf;
  {
      if (lseek(disk, block * FsBSIZE(dev), 0) == -1L
  	    || read(disk, buf, (unsigned) FsBSIZE(dev)) != FsBSIZE(dev)) {
***************
*** 235,243
  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);
      }

--- 287,295 -----
  daddr_t block;
  char *buf;
  {
!     if (lseek(disk, block * FsBSIZE(dev), 0) == -1L
! 	    || read(disk, buf, (unsigned) FsBSIZE(dev)) != FsBSIZE(dev)) {
! 	(void) fprintf(stderr, "%s: can't read block %d: ", cmd_name, block);
  	perror("");
  	exit(1);
      }
***************
*** 243,250
      }
  }
  
! static void
! write_block(daddr_t block, void *buf)
  {
      lseek(disk, block * FsBSIZE(dev), 0);
      if (write(disk, buf, FsBSIZE(dev)) != FsBSIZE(dev)) {

--- 295,303 -----
      }
  }
  
! static void write_block(block, buf)
! daddr_t block;
! char *buf;
  {
      if (lseek(disk, block * FsBSIZE(dev), 0) == -1L
  	    || write(disk, buf, (unsigned) FsBSIZE(dev)) != FsBSIZE(dev)) {
***************
*** 246,254
  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);
      }

--- 299,307 -----
  daddr_t block;
  char *buf;
  {
!     if (lseek(disk, block * FsBSIZE(dev), 0) == -1L
! 	    || write(disk, buf, (unsigned) FsBSIZE(dev)) != FsBSIZE(dev)) {
! 	(void) fprintf(stderr, "%s: can't write block %d: ", cmd_name, block);
  	perror("");
  	exit(1);
      }
***************
*** 254,261
      }
  }
  
! static void
! read_inode(ino_t inode, struct dinode *ino)
  {
      daddr_t block;
  

--- 307,315 -----
      }
  }
  
! static void read_inode(inode, the_ino)
! ino_t inode;
! struct dinode *the_ino;
  {
      daddr_t block;
  
***************
*** 265,271
  	    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)])

--- 319,325 -----
  	    w_ino_blk = block;
  	    read_block(block, inode_block);
  	}
! 	*the_ino = ((struct dinode *)inode_block)[FsITOO(dev, inode)];
      }
      else {
  	*the_ino = ((struct dinode *)&inode_table[block * FsBSIZE(dev)])
***************
*** 268,274
  	*ino = ((struct dinode *)inode_block)[FsITOO(dev, inode)];
      }
      else {
! 	*ino = ((struct dinode *)&inode_table[block * FsBSIZE(dev)])
  	    [FsITOO(dev, inode)];
      }
  }

--- 322,328 -----
  	*the_ino = ((struct dinode *)inode_block)[FsITOO(dev, inode)];
      }
      else {
! 	*the_ino = ((struct dinode *)&inode_table[block * FsBSIZE(dev)])
  	    [FsITOO(dev, inode)];
      }
  }
***************
*** 273,280
      }
  }
  
! static void
! write_inode(ino_t inode, struct dinode *ino)
  {
      daddr_t block;
  

--- 327,335 -----
      }
  }
  
! static void write_inode(inode, the_ino)
! ino_t inode;
! struct dinode *the_ino;
  {
      daddr_t block;
  
***************
*** 284,290
  	    w_ino_blk = block;
  	    read_block(block, inode_block);
  	}
! 	((struct dinode *)inode_block)[FsITOO(dev, inode)] = *ino;
  	write_block(block, inode_block);
      }
      else {

--- 339,345 -----
  	    w_ino_blk = block;
  	    read_block(block, inode_block);
  	}
! 	((struct dinode *)inode_block)[FsITOO(dev, inode)] = *the_ino;
  	write_block(block, inode_block);
      }
      else {
***************
*** 289,295
      }
      else {
  	((struct dinode *)&inode_table[block * FsBSIZE(dev)])
! 	    [FsITOO(dev, inode)] = *ino;
  	write_block(block, &inode_table[block * FsBSIZE(dev)]);
      }
  }

--- 344,350 -----
      }
      else {
  	((struct dinode *)&inode_table[block * FsBSIZE(dev)])
! 	    [FsITOO(dev, inode)] = *the_ino;
  	write_block(block, &inode_table[block * FsBSIZE(dev)]);
      }
  }
***************
*** 294,301
      }
  }
  
! static void
! move_block(daddr_t from, daddr_t to)
  {
      char buffer[FsBSIZE(dev)];
      daddr_t block;

--- 349,357 -----
      }
  }
  
! static void move_block(from, to)
! daddr_t from;
! daddr_t to;
  {
      char buffer[FsBSIZEdev];
      daddr_t block;
***************
*** 297,303
  static void
  move_block(daddr_t from, daddr_t to)
  {
!     char buffer[FsBSIZE(dev)];
      daddr_t block;
  
      if (map[to] != 0)

--- 353,359 -----
  daddr_t from;
  daddr_t to;
  {
!     char buffer[FsBSIZEdev];
      daddr_t block;
  
      if (map[to] != 0)
***************
*** 314,321
  	    map[block] = -to;
  }
  
! static void
! move_inode(ino_t inode)
  {
      int type, i;
      long block[NUM_ADDR];

--- 370,377 -----
  	    map[block] = -to;
  }
  
! static void move_inode(inode)
! ino_t inode;
  {
      int type, i;
      long block[NUM_ADDR];
***************
*** 328,334
      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);

--- 384,391 -----
      if (type == S_IFCHR || type == S_IFBLK)
  	return;
      
!     (void) fprintf(stderr,
! 	    "moving inode %d (size %d)                         \r",
  	inode, ino.di_size);
  
      l3tol(block, ino.di_addr, NUM_ADDR);
***************
*** 349,356
  	move_indirect(block[i], i-FIRST_INDIR);
  }
  
! static void
! move_indirect(daddr_t block, int level)
  {
      int i;
  

--- 406,414 -----
  	move_indirect(block[i], i-FIRST_INDIR);
  }
  
! static void move_indirect(block, level)
! daddr_t block;
! int level;
  {
      int i;
  
***************
*** 378,385
  	move_indirect(((daddr_t *)indir[level])[i], level-1);
  }
  
! static void
! make_hole(void)
  {
      char t_indir[FsBSIZE(dev)];
      daddr_t *p_indir;

--- 436,442 -----
  	move_indirect(((daddr_t *)indir[level])[i], level-1);
  }
  
! static void make_hole()
  {
      char t_indir[FsBSIZEdev];
      daddr_t *p_indir;
***************
*** 381,387
  static void
  make_hole(void)
  {
!     char t_indir[FsBSIZE(dev)];
      daddr_t *p_indir;
      struct dinode t_ino, *p_ino;
      long block[NUM_ADDR];

--- 438,444 -----
  
  static void make_hole()
  {
!     char t_indir[FsBSIZEdev];
      daddr_t *p_indir;
      struct dinode t_ino, *p_ino;
      long block[NUM_ADDR];
***************
*** 393,399
  	--back;
  
      if (next_fill >= back) {
! 	fprintf(stderr, "%s: can't find a free block for %d\n",
  	    cmd_name, next_fill);
  	exit(1);
      }

--- 450,456 -----
  	--back;
  
      if (next_fill >= back) {
! 	(void) fprintf(stderr, "%s: can't find a free block for %d\n",
  	    cmd_name, next_fill);
  	exit(1);
      }
***************
*** 419,425
  	    }
  	}
  	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);

--- 476,482 -----
  	    }
  	}
  	if (i == FsNINDIR(dev)) {
! 	    (void) fprintf(stderr,
  		"%s: panic: can't find %d in indirect block %d\n",
  		cmd_name, next_fill, -map[back]);
  	    exit(1);
***************
*** 424,430
  		cmd_name, next_fill, -map[back]);
  	    exit(1);
  	}
! 	write_block(block[0], p_indir);
      }
      else {
  	if (map[back] == w_ino) {

--- 481,487 -----
  		cmd_name, next_fill, -map[back]);
  	    exit(1);
  	}
! 	write_block(block[0], (char *) p_indir);
      }
      else {
  	if (map[back] == w_ino) {
***************
*** 432,438
  	}
  	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) {

--- 489,495 -----
  	}
  	else {
  	    p_ino = &t_ino;
! 	    read_inode((ino_t) map[back], &t_ino);
  	}
  	l3tol(block, p_ino->di_addr, NUM_ADDR);
  	for (i = 0; i < NUM_ADDR; ++i) {
***************
*** 443,449
  	    }
  	}
  	if (i == NUM_ADDR) {
! 	    fprintf(stderr, "%s: panic: can't find %d in inode %d\n",
  		cmd_name, next_fill, map[back]);
  	    exit(1);
  	}

--- 500,506 -----
  	    }
  	}
  	if (i == NUM_ADDR) {
! 	    (void) fprintf(stderr, "%s: panic: can't find %d in inode %d\n",
  		cmd_name, next_fill, map[back]);
  	    exit(1);
  	}
***************
*** 447,453
  		cmd_name, next_fill, map[back]);
  	    exit(1);
  	}
! 	write_inode(map[back], p_ino);
      }
  }
  

--- 504,510 -----
  		cmd_name, next_fill, map[back]);
  	    exit(1);
  	}
! 	write_inode((ino_t) map[back], p_ino);
      }
  }
  
***************
*** 451,458
      }
  }
  
! static void
! rebuild_free_list(void)
  {
      int free_size, nfree;
      daddr_t free[NICFREE], block;

--- 508,514 -----
      }
  }
  
! static void rebuild_free_list()
  {
      int free_size, nfree;
      daddr_t free[NICFREE], block;
***************
*** 456,462
  {
      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) {

--- 512,518 -----
  {
      int free_size, nfree;
      daddr_t free[NICFREE], block;
!     char buf[FsBSIZEdev];
  
      free_size = filsys.s_fsize - next_fill;
      if (free_size != filsys.s_tfree) {
***************
*** 460,466
  
      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);
      }

--- 516,522 -----
  
      free_size = filsys.s_fsize - next_fill;
      if (free_size != filsys.s_tfree) {
! 	(void) fprintf(stderr, "%s: free list changed size from %d to %d\n",
  	    cmd_name, filsys.s_tfree, free_size);
  	exit(1);
      }
***************
*** 466,473
      }
  
      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) {

--- 522,529 -----
      }
  
      nfree = 1;
!     (void) memset((char *) free, 0, sizeof(free));
!     (void) memset(buf, 0, sizeof(buf));
  
      for (block = filsys.s_fsize - 1; block >= next_fill; --block) {
  	if (nfree == NICFREE) {
***************
*** 472,478
      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));

--- 528,535 -----
      for (block = filsys.s_fsize - 1; block >= next_fill; --block) {
  	if (nfree == NICFREE) {
  	    ((daddr_t *)buf)[0] = nfree;
! 	    (void) memcpy((char *) (&((daddr_t *)buf)[1]), (char *) free,
! 		sizeof(free));
  	    write_block(block, buf);
  	    nfree = 0;
  	    (void) memset((char *) free, 0, sizeof(free));
***************
*** 475,481
  	    memcpy(&((daddr_t *)buf)[1], free, sizeof(free));
  	    write_block(block, buf);
  	    nfree = 0;
! 	    memset(free, 0, sizeof(free));
  	}
  	free[nfree++] = block;
      }

--- 532,538 -----
  		sizeof(free));
  	    write_block(block, buf);
  	    nfree = 0;
! 	    (void) memset((char *) free, 0, sizeof(free));
  	}
  	free[nfree++] = block;
      }
***************
*** 481,486
      }
  
      filsys.s_nfree = nfree;
!     memcpy(&filsys.s_free, free, sizeof(free));
      write_superblk();
  }

--- 538,543 -----
      }
  
      filsys.s_nfree = nfree;
!     (void) memcpy((char *) filsys.s_free, (char *) free, sizeof(free));
      write_superblk();
  }
-- 
George M. Sipe,		       Phone: (404) 447-4731
537 Lakeshore Drive, Berkeley Lake, GA  30136-3035
UUCP: ...!{decvax,linus,rutgers}!gatech!rebel!george

karl@ddsw1.MCS.COM (Karl Denninger) (10/13/89)

Is anyone working on a port of this monster to SCO Xenix 2.3 286/386?

If not, I'm going to dig in, but if someone else has started (or even
better, done it already) perhaps we could save some work.

The differences can't be THAT large..

--
Karl Denninger (karl@ddsw1.MCS.COM, <well-connected>!ddsw1!karl)
Public Access Data Line: [+1 312 566-8911], Voice: [+1 312 566-8910]
Macro Computer Solutions, Inc.		"Quality Solutions at a Fair Price"

bownesrm@beowulf.UUCP (Mr Mojo Risen') (10/14/89)

From article <1989Oct12.214412.29101@ddsw1.MCS.COM>, by karl@ddsw1.MCS.COM (Karl Denninger):
> Is anyone working on a port of this monster to SCO Xenix 2.3 286/386?
> 
> If not, I'm going to dig in, but if someone else has started (or even
> better, done it already) perhaps we could save some work.
> 

	Well I just finished portingit to Xenix System III and it ended
	up taking about 2 hours to track all the subtlties down. I want to
	beat on it a while longer before I give my version to the rest of the 
	world though. Say another week or so.


	bob

-- 
"Reading legal mush can turn your brain to guacamole." - Commodore/Amiga Manual
Bob Bownes, aka iii, aka keptin comrade doktor bobwrench
874 Kari Dr, Eau Claire (Oh Claire!) Wisc, 54701 (715)-835-1934 voice
bownesrm@beowulf.uucp {uunet!crdgw1,uunet!ssi}!beowulf!bownesrm

rick@pcrat.uucp (Rick Richardson) (10/14/89)

In article <1383@rebel.UUCP> george@rebel.UUCP (George M. Sipe) writes:
>I've just tested Andy Fyfe's "packdisk" posted to comp.sources.misc,
>volume 8, issue 93.  It's great!  Thanks Andy.
>
>My system is a UniPlus System V.0 and packdisk worked without fault.

I would like to warn people that even after applying Georges patches,
which are good, there are still some other problems with packdisk.
I haven't been brave enough to test my changes on anything other
than floppy filesystems.  The program has a rather cavalier attitude
towards mixing "int" and "long".  These show up as calculations
that will "lose precision" according to lint, lseek() calls that
pass "int" seek offsets, and printf() calls that use "%d" instead
of "%ld".  The system here that most needs a "packdisk"ing is
a 286, so that's why I noticed these problems.  After fixing
these sorts of things I had to compile it "large model" so that
the needed storage could be malloc'ed, then tested it out on a
floppy filesystem.  It appeared to work, however, it did not
construct a valid freelist (although fsck fixed this).  This
was under Venix System V/286.

All of these things made me too nervous to trust it on a big
filesystem without a backup.  So testing it further will have to 
wait until I get around to shuffling a zillion floppies.  Of course,
the whole reason for using "packdisk" is to avoid having to do
a backup/restore cycle.

Despite the programs deficiencies in a 16 bit environment,
I found the program well organized and conceived, and even
easy to understand in the absence of comments.

-Rick

-- 
Rick Richardson |       Looking for FAX software for UNIX/386 ??????     mention
PC Research,Inc.|                  WE'RE SHIPPING			 your
uunet!pcrat!rick|    Ask about FaxiX - UNIX Facsimile System (tm)        FAX #
(201) 389-8963  | Or JetRoff - troff postprocessor for the HP {Laser,Desk}Jet

zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff) (10/15/89)

I use a similar program by Michael Young (sdti!mjy).  The performance
increase on a optimized file system is very noticable.


-- 
Branch Technology                  |  zeeff@b-tech.ann-arbor.mi.us
                                   |  Ann Arbor, MI

rick@pcrat.uucp (Rick Richardson) (10/15/89)

In article <1989Oct14.130123.1067@pcrat.uucp> rick@pcrat.UUCP (Rick Richardson) writes:
>I would like to warn people that even after applying Georges patches,
>which are good, there are still some other problems with packdisk.

I fixed the stuff for 16 bit machines, Venix/286 filesystems, and
made a performance enhancement.  I present the entire package again
here, with Georges and my changes, because the "patch" file was twice
as big as just sending the whole shar.  I believe that the changes are
all compatible and integrated with the original package.

I've run this on a 44 MB filesystem which was horribly fragmented
(46% fragmented, average seek 139 cyls).  The filesystem is now
less than 2% fragmented with an average seek of 1.02 cyclinders.
I'm done with "packdisk", and I doubt I'll need it again for
several months.

The performance improvement I made (added a reference count) was
critical to the success of using packdisk on 16 bit hardware.
Before the algorithm change, extrapolation led me to estimate
that the process would take some 60 hours to complete.  The
original algorithm was compute bound, moving a block only every
2-4 seconds.  Worse yet, the portion of the algorithm that was
compute bound was approximately quadratic with the size of the
partition being repacked.

After the improvement, the program is nearly I/O bound, and runs
some twenty times faster.  I repacked the 44MB's in 3 hours flat on
an 80286 running at 7.5 Mhz. Standard IBM AT disk controller (3:1),
and a Micropolis 28 msec drive.

Most people will want to compile with -DOLDC, and pay attention to
the definiton of FsBSIZEdev at the beginning of packdisk.c

16 bit folks will need to add -DSMALL and -Ml (large model), and
pay attention to the definition of MAXBLKS.  Large model is used
because you'll need plenty of memory for the block mapping
and reference count arrays.

This program has been needed for years, and I congratulate Andy Fyfe
for getting the job done.

-Rick Richardson
PC Research, Inc.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	COPYRIGHT
#	Makefile
#	packdisk.c
# This archive created: Sun Oct 15 03:08:41 1989
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThis program rearranges the files and directories on a disk
Xso that they appear contiguously.  This is to counteract the
Xfragmentation that occurs after a time under System V.  After
Xthe program finishes all the free space will be collected at
Xthe end of the disk.
X
XThis program was written on an AT&T 3b1 (running unix version 3.5).
XWhile the program was written with portability in mind, it is *not*
Xguaranteed to run on *any* machine, not even the 3b1.  It has,
Xhowever, worked for me.
X
XYou should run fsck before running this program, and again after
Xit's done, just to be sure!
X
XThe program is *slow*.  However, the disk is updated after *every*
Xblock is moved, so the file system should be in a consistent state
Xif the program is halted for any reason (except for the free list,
Xwhich is not rebuilt until the very end).
X
XI don't guarantee that this program won't destroy your disk.
XMake sure you have a backup just in case!!!
X
XTo run the program, simply give the disk device as its only
Xargument.  The program will normally ensure that the given name
Xis a character special device.  If compiled with '-DDEBUG', this
Xcheck is eliminated.  This allows, for example, you to "dd" a
Xfloppy to a disk file (say /tmp/disk) and then run the program
Xwith '/tmp/disk' as its argument.  When running on a real disk,
Xthe disk in question *must* *not* be mounted!!!
X
XRemember:  THIS PROGRAM IS POTENTIALLY VERY DANGEROUS.  Use it
Xat your own risk.
X
X				Andrew Fyfe
X				andy@csvax.caltech.edu
X
X-------------------------------------------------------------------
X *	I took George Sipe's "-DOLDC" fixes, and added fixes
X *	for 16 bit machines "-DSMALL", a compatible fix for filesystems
X *	that store s_nfree as a short (no compile option needed), and
X *	the most important thing -- an algorithm speedup.  Without
X *	the speedup, I estimated that the program would take 60 hours
X *	to run in my environment.  It now takes 3 hours, and could be
X *	improved even more.  Look for "RERSPEEDUP" below.  The speedup
X *	invloves using a reference count to decide whether the block
X *	map needs to be scanned for indirect block references.  When
X *	-DSMALL is defined, the filesystem size is limited to 128K
X *	1024 byte blocks.  These changes worked for me, and should
X *	be compatible with the original version.  Still, USE AT YOUR
X *	OWN RISK!
X *
X *						Rick Richardson
X *						14 October 1989
X *						uunet!pcrat!rick
SHAR_EOF
fi
if test -f 'COPYRIGHT'
then
	echo shar: "will not over-write existing file 'COPYRIGHT'"
else
sed 's/^X//' << \SHAR_EOF > 'COPYRIGHT'
X/*
X * Copyright (c) Andrew Fyfe, 1989
X * All rights reserved.
X * Written by Andrew Fyfe.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. The author is not responsible for the consequences of use of this
X *    software, no matter how awful, even if they arise from flaws in it.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Since few users ever read sources,
X *    credits must appear in the documentation.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.  Since few users
X *    ever read sources, credits must appear in the documentation.
X *
X * 4. This notice may not be removed or altered.
X */
X
X /*
X  * This notice is copied from that included with cnews, which was
X  * written (mostly) by Geoffrey Collyer and Henry Spencer.
X  */
SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#CC = gcc -Wall
XCC = cc
XCFLAGS = -O # System V on 32 bit machine with function prototypes compiler
XCFLAGS = -O -DOLDC # System V on 32 bit machine without function prototypes
XCFLAGS = -Ml -DSMALL -DOLDC -O # Venix/286
XLINTFLAGS = -DSMALL -DOLDC # Venix/286
XLDFLAGS = # -shlib
X
Xpackdisk: packdisk.o
X	$(CC) $(CFLAGS) $(LDFLAGS) -o packdisk packdisk.o
X
Xlint:
X	lint $(LINTFLAGS) packdisk.c > lint.out
X
Xshar:
X	shar -p X README COPYRIGHT Makefile packdisk.c > packdisk.shar
SHAR_EOF
fi
if test -f 'packdisk.c'
then
	echo shar: "will not over-write existing file 'packdisk.c'"
else
sed 's/^X//' << \SHAR_EOF > 'packdisk.c'
X/*
X *
X * This program takes a disk and makes all the files and directories,
X * and the free list, contiguous.
X *
X * 						Andrew Fyfe
X *						7 October 1989
X *
X *						andy@csvax.caltech.edu
X */
X
X/*
X *	I took George Sipe's "-DOLDC" fixes, and added fixes
X *	for 16 bit machines "-DSMALL", a compatible fix for filesystems
X *	that store s_nfree as a short (no compile option needed), and
X *	the most important thing -- an algorithm speedup.  Without
X *	the speedup, I estimated that the program would take 60 hours
X *	to run in my environment.  It now takes 3 hours, and could be
X *	improved even more.  Look for "RERSPEEDUP" below.  The speedup
X *	invloves using a reference count to decide whether the block
X *	map needs to be scanned for indirect block references.  When
X *	-DSMALL is defined, the filesystem size is limited to 128K
X *	1024 byte blocks.  These changes worked for me, and should
X *	be compatible with the original version.  Still, USE AT YOUR
X *	OWN RISK!
X *
X *						Rick Richardson
X *						14 October 1989
X *						uunet!pcrat!rick
X */
X
X#ifndef	OLDC
X#include <stdlib.h>
X#endif
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/filsys.h>
X#include <sys/ino.h>
X#include <sys/stat.h>
X#include <stdio.h>
X
X#ifndef	OLDC
X#define	FsBSIZEdev	FsBSIZE(dev)
X#else
X#define	FsBSIZEdev	1024		/* BE SURE THIS IS OK FOR YOU */
X#endif
X
X#define NUM_ADDR	13
X#define FIRST_INDIR	10   /* 0-9 direct, 10 single, 11 double, 12 triple */
X#define NUM_INDIR	(NUM_ADDR - FIRST_INDIR)
X
Xchar *cmd_name;
Xint disk, dev;
X
Xstruct filsys filsys;
X
Xstruct dinode ino;	/* current working inode, and its number */
Xino_t w_ino;
X
Xchar *inode_block;	/* block containing last read/written inode */
Xdaddr_t w_ino_blk;	/* and its number */
X
Xchar *indir[NUM_INDIR];		/* current working indirect blocks */
Xdaddr_t w_indir[NUM_INDIR];	/* and their numbers */
X
Xdaddr_t next_fill;	/* next (sequential) block to fill */
X
Xchar *inode_table;	/* a cache of the entire inode section of the disk */
X
X#ifdef SMALL
X#define MAXINT	32767			/* Size of an integer */
X#define	MAXBLKS	(128L*1024)		/* Max blocks in a filesystem */
X#define MAPSEG	(4096)			/* # blocks in each array */
X#define MN(BLN) (BLN/MAPSEG)		/* Map number to use */
X#define BN(BLN) (BLN&(MAPSEG-1))	/* Block index in map */
X#define MB(BLN)	(BLN/MAPSEG)][(BLN&(MAPSEG-1))
Xlong *map[MAXBLKS/MAPSEG];
X		/* a map from block numbers to referencing inode/indir block */
Xint *ref[MAXBLKS/MAPSEG];
X		/* reference count for block number (RERSPEEDUP) */
X#else
X#define MAXINT	2147483647		/* Size of an integer */
Xlong *map;	/* a map from block numbers to referencing inode/indir block */
Xint *ref;	/* a map from block numbers to referencing inode/indir block */
X#endif
X
X#ifndef	OLDC
Xstatic void read_superblk(void);
Xstatic void write_superblk(void);
Xstatic void map_inode(ino_t inode);
Xstatic void update_map(long map_entry, daddr_t block, int level);
Xstatic void read_block(daddr_t block, void *buf);
Xstatic void write_block(daddr_t block, void *buf);
Xstatic void read_inode(ino_t inode, struct dinode *buf);
Xstatic void write_inode(ino_t inode, struct dinode *buf);
Xstatic void move_block(daddr_t from, daddr_t to);
Xstatic void move_inode(ino_t inode);
Xstatic void move_indirect(daddr_t block, int level);
Xstatic void make_hole(void);
Xstatic void rebuild_free_list(void);
X
Xextern void l3tol(long *, char *, int length);
Xextern void ltol3(char *, long *, int length);
X#else
X#define	move_indirect		Move_Indirect		/* make uniq */
Xextern char *calloc();
Xextern char *malloc();
Xextern char *memcpy();
Xextern char *memset();
Xextern long lseek();
Xextern void exit();
Xextern void perror();
X
Xstatic void read_superblk();
Xstatic void write_superblk();
Xstatic void map_inode();
Xstatic void update_map();
Xstatic void read_block();
Xstatic void write_block();
Xstatic void read_inode();
Xstatic void write_inode();
Xstatic void move_block();
Xstatic void move_inode();
Xstatic void move_indirect();
Xstatic void make_hole();
Xstatic void rebuild_free_list();
X
Xextern void l3tol();
Xextern void ltol3();
X#endif
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    ino_t inode, total_inodes;
X    daddr_t block;
X    long isize;
X    int	ilimit = -1;
X    int i;
X#ifndef	OLDC
X    char *ctime(long *);
X#ifndef DEBUG
X    struct stat statb;
X    extern int stat(const char *, struct stat *);
X#endif
X#else
X    char *ctime();
X#ifndef DEBUG
X    struct stat statb;
X    extern int stat();
X#endif
X#endif
X
X    cmd_name = argv[0];
X
X    if (argc < 2) {
X	(void) fprintf(stderr, "%s: Usage: %s <file system>\n",
X	    cmd_name, cmd_name);
X	exit(1);
X    }
X
X	if (argc == 3) ilimit = atoi(argv[2]);
X
X#ifndef DEBUG
X    if (stat(argv[1], &statb) < 0) {
X	(void) fprintf(stderr, "%s: can't stat %s: ", cmd_name, argv[1]);
X	perror("");
X	exit(1);
X    }
X    if ((statb.st_mode & S_IFMT) != S_IFCHR) {
X	(void) fprintf(stderr, "%s: %s is not a character device\n",
X	    cmd_name, argv[1]);
X	exit(1);
X    }
X#endif
X
X    disk = open(argv[1], 2, 0);
X    if (disk < 0) {
X	(void) fprintf(stderr, "%s: can't open %s: ", cmd_name, argv[1]);
X	perror("");
X	exit(1);
X    }
X
X    read_superblk();
X
X    total_inodes = (filsys.s_isize - FsITOD(dev, ROOTINO)) * FsINOPB(dev);
X    (void) fprintf(stderr, "File system: name: \"%.6s\", pack: \"%.6s\"\n",
X	filsys.s_fname, filsys.s_fpack);
X    (void) fprintf(stderr, "\tlast modified on %s", ctime(&filsys.s_time));
X    (void) fprintf(stderr,
X	"\ttotal inodes = %d, data blocks = %ld, total = %ld blocks\n",
X	total_inodes, filsys.s_fsize - filsys.s_isize, filsys.s_fsize);
X    (void) fprintf(stderr, "\tfree blocks = %ld, free inodes = %d\n",
X	filsys.s_tfree, filsys.s_tinode);
X
X    for (i = 0; i < NUM_INDIR; ++i) {
X	w_indir[i] = 0;
X	indir[i] = (char *) malloc((unsigned) FsBSIZE(dev));
X	if (indir[i] == 0) {
X	    (void) fprintf(stderr, "%s: can't malloc indir buffer space: ",
X		cmd_name);
X	    perror("");
X	    exit(1);
X	}
X    }
X    w_ino = 0;
X
X#   ifdef SMALL
X	for (isize = filsys.s_fsize, i = 0; isize > 0; ++i)
X	{
X	    map[i] = (long *) calloc((unsigned) MAPSEG, sizeof(long));
X	    ref[i] = (int *) calloc((unsigned) MAPSEG, sizeof(int));
X	    isize -= MAPSEG;
X	    if (map[i] == 0 || ref[i] == 0) {
X		(void) fprintf(stderr, "%s: can't calloc map: ", cmd_name);
X		perror("");
X		exit(1);
X	    }
X	}
X#   else
X	map = (long *) calloc((unsigned) filsys.s_fsize, sizeof(*map));
X	ref = (int *) calloc((unsigned) filsys.s_fsize, sizeof(*ref));
X	if (map == 0 || ref == 0) {
X	    (void) fprintf(stderr, "%s: can't calloc map: ", cmd_name);
X	    perror("");
X	    exit(1);
X	}
X#   endif
X
X    isize = (long) filsys.s_isize * FsBSIZE(dev);
X    if (isize > MAXINT)
X	inode_table = NULL;
X    else
X        inode_table = (char *) malloc((unsigned) isize);
X    if (inode_table == 0) {
X	(void) fprintf(stderr, "%s: can't malloc space for inode table\n",
X	    cmd_name);
X	(void) fprintf(stderr, "%s: that's OK, I will just run slower\n",
X	    cmd_name);
X	w_ino_blk = 0;
X	inode_block = (char *) malloc((unsigned) FsBSIZE(dev));
X	if (inode_block == 0) {
X	    (void) fprintf(stderr, "%s: can't malloc inode buffer space: %u",
X		cmd_name, FsBSIZE(dev));
X	    perror("");
X	    exit(1);
X	}
X    }
X    else
X	for (block = FsITOD(dev, ROOTINO); block < filsys.s_isize; ++block)
X	    read_block(block, &inode_table[block * FsBSIZE(dev)]);
X
X    (void) fprintf(stderr, "mapping...");
X    for (inode = ROOTINO; inode <= total_inodes; ++inode)
X	map_inode(inode);
X    (void) fprintf(stderr, "done\n");
X
X    next_fill = filsys.s_isize;
X    if (ilimit >= 0)
X	    for (inode = ROOTINO; inode <= ilimit; ++inode)
X		move_inode(inode);
X    else
X	    for (inode = ROOTINO; inode <= total_inodes; ++inode)
X		move_inode(inode);
X
X    (void) fprintf(stderr, "\nrebuilding the free list\n");
X    rebuild_free_list();
X
X    (void) fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
X
X    (void) close(disk);
X    exit(0);
X    /* NOTREACHED */
X}
X
Xstatic void read_superblk()
X{
X    if (lseek(disk, (long) SUPERBOFF, 0) != (long) SUPERBOFF) {
X	(void) fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
X	perror("");
X	exit(1);
X    }
X    if (read(disk, (char *) &filsys, sizeof(filsys)) != sizeof(filsys)) {
X	(void) fprintf(stderr, "%s: can't read superblock: ", cmd_name);
X	perror("");
X	exit(1);
X    }
X    if (filsys.s_magic != FsMAGIC) {
X	(void) fprintf(stderr, "%s: invalid superblock magic number\n",
X	    cmd_name);
X	exit(1);
X    }
X    dev = (filsys.s_type == Fs2b) ? Fs2BLK : 0;
X}
X
Xstatic void write_superblk()
X{
X    if (lseek(disk, (long) SUPERBOFF, 0) == -1L) {
X	(void) fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
X	perror("");
X	exit(1);
X    }
X    if (write(disk, (char *) &filsys, sizeof(filsys)) != sizeof(filsys)) {
X	(void) fprintf(stderr, "%s: can't write superblock: ", cmd_name);
X	perror("");
X	exit(1);
X    }
X}
X
Xstatic void map_inode(inode)
Xino_t inode;
X{
X    int type, i;
X    long block[NUM_ADDR];
X
X    read_inode(inode, &ino);
X    if (ino.di_mode == 0)
X	return;
X    type = ino.di_mode & S_IFMT;
X    if (type == S_IFCHR || type == S_IFBLK)
X	return;
X
X    l3tol(block, ino.di_addr, NUM_ADDR);
X    for (i = 0; i < NUM_ADDR; ++i)
X	if (block[i] != 0)
X	    update_map((long) inode, block[i],
X		(i < FIRST_INDIR) ? 0 : (i - FIRST_INDIR + 1));
X}
X
Xstatic void update_map(map_entry, block, level)
Xlong map_entry;
Xdaddr_t block;
Xint level;
X{
X    int i;
X
X    if (map[MB(block)] != 0) {
X	(void) fprintf(stderr, "%s: duplicate block %d in %d and %d\n",
X	    cmd_name, block, map[block], map_entry);
X	exit(1);
X    }
X    map[MB(block)] = map_entry;
X
X    if (map_entry < 0)
X	++ref[MB(-map_entry)];	/* RERSPEEDUP: maintain reference count */
X				/* for indirect blocks */
X
X    if (level == 0)
X	return;
X
X    --level;
X    read_block(block, indir[level]);
X    for (i = 0; i < FsNINDIR(dev); ++i)
X	if (((daddr_t *)indir[level])[i] != 0)
X	    update_map(-block, ((daddr_t *)indir[level])[i], level);
X}
X
Xstatic void read_block(block, buf)
Xdaddr_t block;
Xchar *buf;
X{
X    if (lseek(disk, (long) block * FsBSIZE(dev), 0) == -1L) {
X	(void) fprintf(stderr, "%s: can't seek block %ld, addr %ld: ",
X		cmd_name, block, (long) block * FsBSIZE(dev) );
X	perror("");
X	exit(1);
X    }
X    if (read(disk, buf, (unsigned) FsBSIZE(dev)) != FsBSIZE(dev)) {
X	(void) fprintf(stderr, "%s: can't read block %ld, addr %ld: ",
X		cmd_name, block, (long) block * FsBSIZE(dev) );
X	perror("");
X	exit(1);
X    }
X}
X
Xstatic void write_block(block, buf)
Xdaddr_t block;
Xchar *buf;
X{
X    if (lseek(disk, (long) block * FsBSIZE(dev), 0) == -1L
X	    || write(disk, buf, (unsigned) FsBSIZE(dev)) != FsBSIZE(dev)) {
X	(void) fprintf(stderr, "%s: can't write block %d: ", cmd_name, block);
X	perror("");
X	exit(1);
X    }
X}
X
Xstatic void read_inode(inode, the_ino)
Xino_t inode;
Xstruct dinode *the_ino;
X{
X    daddr_t block;
X
X    block = FsITOD(dev, inode);
X    if (inode_table == 0) {
X	if (w_ino_blk != block) {
X	    w_ino_blk = block;
X	    read_block(block, inode_block);
X	}
X	*the_ino = ((struct dinode *)inode_block)[FsITOO(dev, inode)];
X    }
X    else {
X	*the_ino = ((struct dinode *)&inode_table[block * FsBSIZE(dev)])
X	    [FsITOO(dev, inode)];
X    }
X}
X
Xstatic void write_inode(inode, the_ino)
Xino_t inode;
Xstruct dinode *the_ino;
X{
X    daddr_t block;
X
X    block = FsITOD(dev, inode);
X    if (inode_table == 0) {
X	if (w_ino_blk != block) {
X	    w_ino_blk = block;
X	    read_block(block, inode_block);
X	}
X	((struct dinode *)inode_block)[FsITOO(dev, inode)] = *the_ino;
X	write_block(block, inode_block);
X    }
X    else {
X	((struct dinode *)&inode_table[block * FsBSIZE(dev)])
X	    [FsITOO(dev, inode)] = *the_ino;
X	write_block(block, &inode_table[block * FsBSIZE(dev)]);
X    }
X}
X
Xstatic void move_block(from, to)
Xdaddr_t from;
Xdaddr_t to;
X{
X    char buffer[FsBSIZEdev];
X    daddr_t block;
X    daddr_t negfrom = -from;
X    daddr_t negto = -to;
X#   ifdef SMALL
X	register int bn, seg;
X	long *mapp;
X#   endif
X
X    if (map[MB(to)] != 0)
X	make_hole();
X
X    read_block(from, buffer);
X    write_block(to, buffer);
X
X    map[MB(to)] = map[MB(from)];
X    ref[MB(to)] = ref[MB(from)];
X    map[MB(from)] = 0;
X    ref[MB(from)] = 0;
X
X    if (ref[MB(to)])
X    {
X	/* RERSPEEDUP
X	 * The original algorithm did the "for" loop every time
X	 * a block was moved, searching for indirect blocks which
X	 * contain the "from" disk address.  I added a reference
X	 * count so we only do the search if there is at least one
X	 * indirect block that has the address.  This was a twenty
X	 * fold improvement in speed, and changed the program from
X	 * being compute bound to being I/O bound most of the time.
X	 * In fact, you could abort the for loop early once you've
X	 * found "ref[]" indirect blocks.  I didn't, since the
X	 * number of files with indirect blocks was only 10% of all
X	 * of my files.  The two second delay for the search proved
X	 * convenient for hitting INTERRUPT in case I wanted to stop.
X	 *
X	 * I also tuned the loop a little for the braindamage of having
X	 * to segment the map on a 16 bit machine.
X	 */
X
X	(void) fprintf(stderr, "%c", 007);	/* Beep */
X#	ifdef SMALL
X	    bn = BN(filsys.s_isize); seg = MN(filsys.s_isize);
X	    mapp = &map[seg][bn];
X	    for (block = filsys.s_isize; block < filsys.s_fsize; )
X	    {
X		if (*mapp == negfrom)
X			*mapp = negto;
X		++block; ++mapp;
X		if (++bn >= MAPSEG)
X		{
X			++seg; bn = 0; mapp = map[seg];
X		}
X	    }
X#	else
X	    for (block = filsys.s_isize; block < filsys.s_fsize; ++block)
X		if (map[MB(block)] == negfrom)
X		    map[MB(block)] = negto;
X#	endif
X    }
X}
X
Xstatic void move_inode(inode)
Xino_t inode;
X{
X    int type, i;
X    long block[NUM_ADDR];
X
X    read_inode(inode, &ino);
X    w_ino = inode;
X    if (ino.di_mode == 0)
X	return;
X    type = ino.di_mode & S_IFMT;
X    if (type == S_IFCHR || type == S_IFBLK)
X	return;
X    
X    (void) fprintf(stderr,
X	    "moving inode %d (size %ld)                         \r",
X	inode, ino.di_size);
X
X    l3tol(block, ino.di_addr, NUM_ADDR);
X    for (i = 0; i < NUM_ADDR; ++i) {
X	if (block[i] == 0)
X	    continue;
X	if (block[i] != next_fill) {
X	    move_block(block[i], next_fill);
X	    l3tol(block, ino.di_addr, NUM_ADDR);
X	    block[i] = next_fill;
X	    ltol3(ino.di_addr, block, NUM_ADDR);
X	    write_inode(inode, &ino);
X	}
X	++next_fill;
X    }
X    
X    for (i = FIRST_INDIR; i < NUM_ADDR; ++i)
X	move_indirect(block[i], i-FIRST_INDIR);
X}
X
Xstatic void move_indirect(block, level)
Xdaddr_t block;
Xint level;
X{
X    int i;
X
X    if (block == 0)
X	return;
X
X    read_block(block, indir[level]);
X    w_indir[level] = block;
X
X    for (i = 0; i < FsNINDIR(dev); ++i) {
X	if (((daddr_t *)indir[level])[i] == 0)
X	    continue;
X	if (((daddr_t *)indir[level])[i] != next_fill) {
X	    move_block(((daddr_t *)indir[level])[i], next_fill);
X	    ((daddr_t *)indir[level])[i] = next_fill;
X	    write_block(block, indir[level]);
X	}
X	++next_fill;
X    }
X
X    if (level == 0)
X	return;
X
X    for (i = 0; i < FsNINDIR(dev); ++i)
X	move_indirect(((daddr_t *)indir[level])[i], level-1);
X}
X
Xstatic void make_hole()
X{
X    char t_indir[FsBSIZEdev];
X    daddr_t *p_indir;
X    struct dinode t_ino, *p_ino;
X    long block[NUM_ADDR];
X    daddr_t back;
X    int i;
X
X    back = filsys.s_fsize - 1;
X    while (next_fill < back && map[MB(back)] != 0)
X	--back;
X
X    if (next_fill >= back) {
X	(void) fprintf(stderr, "%s: can't find a free block for %d\n",
X	    cmd_name, next_fill);
X	exit(1);
X    }
X
X    move_block(next_fill, back);
X
X    if (map[MB(back)] < 0) {
X	block[0] = -map[MB(back)];
X	for (i = 0; i < NUM_INDIR; ++i)
X	    if (block[0] == w_indir[i])
X		break;
X	if (i < NUM_INDIR) {
X	    p_indir = (daddr_t *)indir[i];
X	}
X	else {
X	    p_indir = (daddr_t *)t_indir;
X	    read_block(block[0], t_indir);
X	}
X	for (i = 0; i < FsNINDIR(dev); ++i) {
X	    if (p_indir[i] == next_fill) {
X		p_indir[i] = back;
X		break;
X	    }
X	}
X	if (i == FsNINDIR(dev)) {
X	    (void) fprintf(stderr,
X		"%s: panic: can't find %d in indirect block %d\n",
X		cmd_name, next_fill, -map[MB(back)]);
X	    exit(1);
X	}
X	write_block(block[0], (char *) p_indir);
X    }
X    else {
X	if (map[MB(back)] == w_ino) {
X	    p_ino = &ino;
X	}
X	else {
X	    p_ino = &t_ino;
X	    read_inode((ino_t) map[MB(back)], &t_ino);
X	}
X	l3tol(block, p_ino->di_addr, NUM_ADDR);
X	for (i = 0; i < NUM_ADDR; ++i) {
X	    if (block[i] == next_fill) {
X		block[i] = back;
X		ltol3(p_ino->di_addr, block, NUM_ADDR);
X		break;
X	    }
X	}
X	if (i == NUM_ADDR) {
X	    (void) fprintf(stderr, "%s: panic: can't find %d in inode %d\n",
X		cmd_name, next_fill, map[MB(back)]);
X	    exit(1);
X	}
X	write_inode((ino_t) map[MB(back)], p_ino);
X    }
X}
X
Xstatic void rebuild_free_list()
X{
X    long free_size, nfree;
X    daddr_t free[NICFREE], block;
X    char buf[FsBSIZEdev];
X
X    free_size = filsys.s_fsize - next_fill;
X    if (free_size != filsys.s_tfree) {
X	(void) fprintf(stderr, "%s: free list changed size from %ld to %ld\n",
X	    cmd_name, filsys.s_tfree, free_size);
X	exit(1);
X    }
X
X    nfree = 1;
X    (void) memset((char *) free, 0, sizeof(free));
X    (void) memset(buf, 0, sizeof(buf));
X
X    for (block = filsys.s_fsize - 1; block >= next_fill; --block) {
X	if (nfree == NICFREE) {
X	    if (sizeof(filsys.s_nfree) == sizeof(short))
X	    {	/* Venix/286 has a short s_nfree member */
X		    ((short *)buf)[0] = nfree;
X		    (void) memcpy((char *) (&((short *)buf)[1]),
X			(char *) free, sizeof(free));
X	    }
X	    else
X	    {	/* The usual case for System V */
X		    ((daddr_t *)buf)[0] = nfree;
X		    (void) memcpy((char *) (&((daddr_t *)buf)[1]),
X			(char *) free, sizeof(free));
X	    }
X	    write_block(block, buf);
X	    nfree = 0;
X	    (void) memset((char *) free, 0, sizeof(free));
X	}
X	free[nfree++] = block;
X    }
X
X    filsys.s_nfree = nfree;
X    (void) memcpy((char *) filsys.s_free, (char *) free, sizeof(free));
X    write_superblk();
X}
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
Rick Richardson |       Looking for FAX software for UNIX/386 ??????     mention
PC Research,Inc.|                  WE'RE SHIPPING			 your
uunet!pcrat!rick|    Ask about FaxiX - UNIX Facsimile System (tm)        FAX #
(201) 389-8963  | Or JetRoff - troff postprocessor for the HP {Laser,Desk}Jet

karl@sugar.hackercorp.com (Karl Lehenbauer) (10/16/89)

In article <1989Oct14.130123.1067@pcrat.uucp> rick@pcrat.UUCP (Rick Richardson)
writes warning about trying to use packdisk on 16-bit machines.

Thanks for mentioning that, I forgot.  Yes, 286 guys and such, this program
needs a good deal of scrutiny before using it on your filesystems.  Considering
all the hassle Microport had with 16-bit integer errors (restricting filesystems
to 32 MB), I'd be very careful indeed.
-- 
-- uunet!sugar!karl	"There is hopeful symbolism in the fact that 
-- 			 flags do not wave in a vacuum."  -- Arthur C. Clarke
-- Usenet access: (713) 438-5018

chuckb@hounix.UUCP (Chuck Bentley) (10/17/89)

In article <1989Oct15.073237.2472@pcrat.uucp>, rick@pcrat.uucp (Rick Richardson) writes:
> I've run this on a 44 MB filesystem which was horribly fragmented
> (46% fragmented, average seek 139 cyls).  The filesystem is now
> less than 2% fragmented with an average seek of 1.02 cyclinders.

What do you use to measure this?  Is it public domain?  I haven't seen
anything in the archives that would indicate that it would give this
kind on information.  Then again I've been told I need glasses. :-)

		Chuck..

rick@pcrat.uucp (Rick Richardson) (10/17/89)

In article <1989Oct15.073237.2472@pcrat.uucp> rick@pcrat.UUCP (Rick Richardson) writes:
>
>I fixed the stuff for 16 bit machines, Venix/286 filesystems, and
>made a performance enhancement....

It turned out that the free list tweak I made for Venix/286 wasn't portable.
So I've made it a compile time option.  It wouldn't cause any damage, since
fsck is perfectly capable of building a clean free list.

It also turned out that I missed defining "MB" when SMALL is not defined.
The definition was obvious: "#define MB(BLN) BLN".

Here is a context diff for "patch" to fix these minor glitches.
Apply it to _my_ version posted to comp.sources.d, not to the original
source.

Also, a couple of people have complained that I didn't post my version
to comp.sources.misc.  Hey, that's not my job!  Its up to the original
author to post the changed ("final") version for posterity.  My
version is mearly a "suggestion".  If the author fails to complete
his duties within several months, *then and only then* I'd consider
posting my changed version to comp.sources.misc for archiving.

-Rick

*** old/Makefile	Tue Oct 17 03:10:29 1989
--- Makefile	Tue Oct 17 03:20:42 1989
***************
*** 1,3
  #CC = gcc -Wall
  CC = cc
  CFLAGS = -O # System V on 32 bit machine with function prototypes compiler

--- 1,13 -----
+ #
+ #	Makefile for packdisk
+ #	Options:
+ #		-DOLDC		Compiler doesn't have function prototypes
+ #		-DSMALL		Machine is 16 bit (80286)
+ #		-DSHORTFREE	UNIX (e.g. Venix.286) stores the number
+ #				of free block numbers in free disk blocks
+ #				as a short instead of a long (despite what
+ #				the fs(4) manual says).
+ #
  #CC = gcc -Wall
  CC = cc
  CFLAGS = -O # System V on 32 bit machine with function prototypes compiler
***************
*** 1,6
  #CC = gcc -Wall
  CC = cc
  CFLAGS = -O # System V on 32 bit machine with function prototypes compiler
  CFLAGS = -O -DOLDC # System V on 32 bit machine without function prototypes
  CFLAGS = -Ml -DSMALL -DOLDC -O # Venix/286
  LINTFLAGS = -DSMALL -DOLDC # Venix/286

--- 11,17 -----
  #CC = gcc -Wall
  CC = cc
  CFLAGS = -O # System V on 32 bit machine with function prototypes compiler
+ CFLAGS = -Ml -DSMALL -DOLDC -DSHORTFREE -O # Venix/286
  CFLAGS = -O -DOLDC # System V on 32 bit machine without function prototypes
  
  LINTFLAGS = -DSMALL -DOLDC # Venix/286
***************
*** 2,8
  CC = cc
  CFLAGS = -O # System V on 32 bit machine with function prototypes compiler
  CFLAGS = -O -DOLDC # System V on 32 bit machine without function prototypes
! CFLAGS = -Ml -DSMALL -DOLDC -O # Venix/286
  LINTFLAGS = -DSMALL -DOLDC # Venix/286
  LDFLAGS = # -shlib
  

--- 13,19 -----
  CFLAGS = -O # System V on 32 bit machine with function prototypes compiler
  CFLAGS = -Ml -DSMALL -DOLDC -DSHORTFREE -O # Venix/286
  CFLAGS = -O -DOLDC # System V on 32 bit machine without function prototypes
! 
  LINTFLAGS = -DSMALL -DOLDC # Venix/286
  LDFLAGS = # -shlib
  
*** old/packdisk.c	Tue Oct 17 03:10:33 1989
--- packdisk.c	Tue Oct 17 03:25:30 1989
***************
*** 17,23
   *	the speedup, I estimated that the program would take 60 hours
   *	to run in my environment.  It now takes 3 hours, and could be
   *	improved even more.  Look for "RERSPEEDUP" below.  The speedup
!  *	invloves using a reference count to decide whether the block
   *	map needs to be scanned for indirect block references.  When
   *	-DSMALL is defined, the filesystem size is limited to 128K
   *	1024 byte blocks.  These changes worked for me, and should

--- 17,23 -----
   *	the speedup, I estimated that the program would take 60 hours
   *	to run in my environment.  It now takes 3 hours, and could be
   *	improved even more.  Look for "RERSPEEDUP" below.  The speedup
!  *	involves using a reference count to decide whether the block
   *	map needs to be scanned for indirect block references.  When
   *	-DSMALL is defined, the filesystem size is limited to 128K
   *	1024 byte blocks.  These changes worked for me, and should
***************
*** 27,32
   *						Rick Richardson
   *						14 October 1989
   *						uunet!pcrat!rick
   */
  
  #ifndef	OLDC

--- 27,42 -----
   *						Rick Richardson
   *						14 October 1989
   *						uunet!pcrat!rick
+  *
+  *	It turned out that the change I made to handle Venix's weirdness
+  *	with the s_nfree field (in free disk blocks only) wasn't portable.
+  *	I added a compile time option to handle it, -DSHORTFREE.  Most
+  *	UNIXes won't need it.  I also added the missing "MB" macro for
+  *	when -DSMALL isn't supplied.
+  *						Rick Richardson
+  *						17 October 1989
+  *						uunet!pcrat!rick
+  *
   */
  
  #ifndef	OLDC
***************
*** 80,85
  		/* reference count for block number (RERSPEEDUP) */
  #else
  #define MAXINT	2147483647		/* Size of an integer */
  long *map;	/* a map from block numbers to referencing inode/indir block */
  int *ref;	/* a map from block numbers to referencing inode/indir block */
  #endif

--- 90,96 -----
  		/* reference count for block number (RERSPEEDUP) */
  #else
  #define MAXINT	2147483647		/* Size of an integer */
+ #define	MB(BLN)	BLN
  long *map;	/* a map from block numbers to referencing inode/indir block */
  int *ref;	/* a map from block numbers to referencing inode/indir block */
  #endif
***************
*** 651,657
  
      for (block = filsys.s_fsize - 1; block >= next_fill; --block) {
  	if (nfree == NICFREE) {
! 	    if (sizeof(filsys.s_nfree) == sizeof(short))
  	    {	/* Venix/286 has a short s_nfree member */
  		    ((short *)buf)[0] = nfree;
  		    (void) memcpy((char *) (&((short *)buf)[1]),

--- 662,668 -----
  
      for (block = filsys.s_fsize - 1; block >= next_fill; --block) {
  	if (nfree == NICFREE) {
! #	    ifdef SHORTFREE
  	    {	/* Venix/286 has a short s_nfree member */
  		    ((short *)buf)[0] = nfree;
  		    (void) memcpy((char *) (&((short *)buf)[1]),
***************
*** 657,663
  		    (void) memcpy((char *) (&((short *)buf)[1]),
  			(char *) free, sizeof(free));
  	    }
! 	    else
  	    {	/* The usual case for System V */
  		    ((daddr_t *)buf)[0] = nfree;
  		    (void) memcpy((char *) (&((daddr_t *)buf)[1]),

--- 668,674 -----
  		    (void) memcpy((char *) (&((short *)buf)[1]),
  			(char *) free, sizeof(free));
  	    }
! #	    else
  	    {	/* The usual case for System V */
  		    ((daddr_t *)buf)[0] = nfree;
  		    (void) memcpy((char *) (&((daddr_t *)buf)[1]),
***************
*** 663,668
  		    (void) memcpy((char *) (&((daddr_t *)buf)[1]),
  			(char *) free, sizeof(free));
  	    }
  	    write_block(block, buf);
  	    nfree = 0;
  	    (void) memset((char *) free, 0, sizeof(free));

--- 674,680 -----
  		    (void) memcpy((char *) (&((daddr_t *)buf)[1]),
  			(char *) free, sizeof(free));
  	    }
+ #	    endif
  	    write_block(block, buf);
  	    nfree = 0;
  	    (void) memset((char *) free, 0, sizeof(free));
-- 
Rick Richardson |       Looking for FAX software for UNIX/386 ??????     mention
PC Research,Inc.|                  WE'RE SHIPPING			 your
uunet!pcrat!rick|    Ask about FaxiX - UNIX Facsimile System (tm)        FAX #
(201) 389-8963  | Or JetRoff - troff postprocessor for the HP {Laser,Desk}Jet

karl@sugar.hackercorp.com (Karl Lehenbauer) (10/18/89)

Here is a patch to the version of packdisk that was recently posted containing
i286 fixes and radical performance improvements.

This patch makes packdisk compile under Unix System V/386 release 3.2, and
may apply to other 3.2 release.  The #ifdef'ed code is activated by doing
a -DI386 on the command line.

Also there was a problem in that the small memory changes made the normal large
memory stuff not compile.  The problem was that the MB macro was not defined
if large model.

This is a great tool, thanks to the author and those producing patches,
especially the performance improvements.

Again, remember to always backup before using and run fsck before and after.
-karl
---------------------------- cut here ----------------------------
*** packdisk.c.orig	Tue Oct 17 20:01:28 1989
--- packdisk.c	Mon Oct 16 01:25:33 1989
***************
*** 34,39
  #endif
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/filsys.h>
  #include <sys/ino.h>
  #include <sys/stat.h>

--- 34,44 -----
  #endif
  #include <sys/types.h>
  #include <sys/param.h>
+ #ifdef I386
+ #include <sys/fs/s5param.h>
+ #include <sys/fs/s5filsys.h>
+ #include <sys/fs/s5macros.h>
+ #else
  #include <sys/filsys.h>
  #endif
  #include <sys/ino.h>
***************
*** 35,40
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/filsys.h>
  #include <sys/ino.h>
  #include <sys/stat.h>
  #include <stdio.h>

--- 40,46 -----
  #include <sys/fs/s5macros.h>
  #else
  #include <sys/filsys.h>
+ #endif
  #include <sys/ino.h>
  #include <sys/stat.h>
  #include <stdio.h>
***************
*** 39,44
  #include <sys/stat.h>
  #include <stdio.h>
  
  #ifndef	OLDC
  #define	FsBSIZEdev	FsBSIZE(dev)
  #else

--- 45,54 -----
  #include <sys/stat.h>
  #include <stdio.h>
  
+ #ifdef I386
+ #define ROOTINO S5ROOTINO
+ #endif
+ 
  #ifndef	OLDC
  #define	FsBSIZEdev	FsBSIZE(dev)
  #else
***************
*** 82,87
  #define MAXINT	2147483647		/* Size of an integer */
  long *map;	/* a map from block numbers to referencing inode/indir block */
  int *ref;	/* a map from block numbers to referencing inode/indir block */
  #endif
  
  #ifndef	OLDC

--- 92,98 -----
  #define MAXINT	2147483647		/* Size of an integer */
  long *map;	/* a map from block numbers to referencing inode/indir block */
  int *ref;	/* a map from block numbers to referencing inode/indir block */
+ #define MB(BLN) (BLN)
  #endif
  
  #ifndef	OLDC
-- 
-- uunet!sugar!karl	"There is hopeful symbolism in the fact that 
-- 			 flags do not wave in a vacuum."  -- Arthur C. Clarke
-- Usenet access: (713) 438-5018

roe@sobmips.UUCP (r.peterson) (10/21/89)

From article <3648@hounix.UUCP>, by chuckb@hounix.UUCP (Chuck Bentley):

[ stuff about frag measurement deleted ]
> 
> What do you use to measure this?  Is it public domain?  I haven't seen
> anything in the archives that would indicate that it would give this
> kind on information.  Then again I've been told I need glasses. :-)

Try comp.sources.misc, volume5, fsanalyze4.1 - I just ported it to
the NCR tower/32 (1.03.02/2.01) and the mips(4.0) (with some hassles) -
but it works just fine.
-- 
					Roe Peterson
					{attcan,mcgill-vision,telly}!sobeco!roe

jfh@rpp386.cactus.org (John F. Haugh II) (10/21/89)

In article <1989Oct21.013237.29071@sobmips.UUCP> roe@sobmips.UUCP (r.peterson) writes:
>From article <3648@hounix.UUCP>, by chuckb@hounix.UUCP (Chuck Bentley):
>> What do you use to measure this?  Is it public domain?  I haven't seen
>> anything in the archives that would indicate that it would give this
>> kind on information.  Then again I've been told I need glasses. :-)
>
>Try comp.sources.misc, volume5, fsanalyze4.1 - I just ported it to
>the NCR tower/32 (1.03.02/2.01) and the mips(4.0) (with some hassles) -
>but it works just fine.

I have it here.  The sizes and filenames are

% ls -s /usr/archive/fsanalyze/*
  46 /usr/archive/fsanalyze/fsanal.sh.1.Z
  44 /usr/archive/fsanalyze/fsanal.sh.2.Z
  28 /usr/archive/fsanalyze/fsanal.sh.3.Z

and the L.sys line is

rpp386 Any ACU 2400 15128328835 in:--in:--in: uucp
-- 
John F. Haugh II                        +-Things you didn't want to know:------
VoiceNet: (512) 832-8832   Data: -8835  | The real meaning of EMACS is ...
InterNet: jfh@rpp386.cactus.org         |   ... EMACS makes a computer slow.
UUCPNet:  {texbell|bigtex}!rpp386!jfh   +--<><--<><--<><--<><--<><--<><--<><---