Remove treecmp utility (Bug#310, reported by John Peace)
This commit is contained in:
		
							parent
							
								
									2ac8124914
								
							
						
					
					
						commit
						bc029d0bc6
					
				@ -193,7 +193,6 @@ ALL	= \
 | 
			
		||||
	top \
 | 
			
		||||
	tr \
 | 
			
		||||
	truncate \
 | 
			
		||||
	treecmp \
 | 
			
		||||
	tsort \
 | 
			
		||||
	ttt \
 | 
			
		||||
	tty \
 | 
			
		||||
@ -827,10 +826,6 @@ tsort:	tsort.c
 | 
			
		||||
	$(CCLD) -o $@ $<
 | 
			
		||||
	@install -S 4kw $@
 | 
			
		||||
 | 
			
		||||
treecmp:	treecmp.c
 | 
			
		||||
	$(CCLD) -o $@ $<
 | 
			
		||||
	@install -S 4kw $@
 | 
			
		||||
 | 
			
		||||
truncate:	truncate.c
 | 
			
		||||
	$(CCLD) -o $@ $<
 | 
			
		||||
	@install -S 4kw $@
 | 
			
		||||
@ -1091,7 +1086,6 @@ install:	\
 | 
			
		||||
	/usr/bin/top \
 | 
			
		||||
	/usr/bin/touch \
 | 
			
		||||
	/usr/bin/tr \
 | 
			
		||||
	/usr/bin/treecmp \
 | 
			
		||||
	/usr/bin/truncate \
 | 
			
		||||
	/usr/bin/tsort \
 | 
			
		||||
	/usr/bin/ttt \
 | 
			
		||||
@ -1641,9 +1635,6 @@ install:	\
 | 
			
		||||
/usr/bin/tr:	tr
 | 
			
		||||
	install -cs -o bin $< $@
 | 
			
		||||
 | 
			
		||||
/usr/bin/treecmp:	treecmp
 | 
			
		||||
	install -cs -o bin $< $@
 | 
			
		||||
 | 
			
		||||
/usr/bin/truncate:	truncate
 | 
			
		||||
	install -cs -o bin $< $@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,327 +0,0 @@
 | 
			
		||||
/* treecmp - compare two trees		Author: Andy Tanenbaum */
 | 
			
		||||
 | 
			
		||||
/* This program recursively compares two trees and reports on differences.
 | 
			
		||||
 * It can be used, for example, when a project consists of a large number
 | 
			
		||||
 * of files and directories.  When a new release (i.e., a new tree) has been
 | 
			
		||||
 * prepared, the old and new tree can be compared to give a list of what has
 | 
			
		||||
 * changed.  The algorithm used is that the second tree is recursively
 | 
			
		||||
 * descended and for each file or directory found, the corresponding one in
 | 
			
		||||
 * the other tree checked.  The two arguments are not completely symmetric
 | 
			
		||||
 * because the second tree is descended, not the first one, but reversing
 | 
			
		||||
 * the arguments will still detect all the differences, only they will be
 | 
			
		||||
 * printed in a different order.  The program needs lots of stack space
 | 
			
		||||
 * because routines with local arrays are called recursively. The call is
 | 
			
		||||
 *    treecmp [-cv] old_dir new_dir
 | 
			
		||||
 * The -v flag (verbose) prints the directory names as they are processed.
 | 
			
		||||
 * The -c flag (changes) just prints the names of changed and new files.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#define BUFSIZE 4096		/* size of file buffers */
 | 
			
		||||
#define MAXPATH 128		/* longest acceptable path */
 | 
			
		||||
#define DIRENTLEN 14		/* number of characters in a file name */
 | 
			
		||||
 | 
			
		||||
struct dirstruct {		/* layout of a directory entry */
 | 
			
		||||
  ino_t inum;
 | 
			
		||||
  char fname[DIRENTLEN];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct stat stat1, stat2;	/* stat buffers */
 | 
			
		||||
 | 
			
		||||
char buf1[BUFSIZE];		/* used for comparing bufs */
 | 
			
		||||
char buf2[BUFSIZE];		/* used for comparing bufs */
 | 
			
		||||
 | 
			
		||||
int changes;			/* set on -c flag */
 | 
			
		||||
int verbose;			/* set on -v flag */
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(int main, (int argc, char **argv));
 | 
			
		||||
_PROTOTYPE(void compare, (char *old, char *new));
 | 
			
		||||
_PROTOTYPE(void regular, (char *old, char *new));
 | 
			
		||||
_PROTOTYPE(void directory, (char *old, char *new));
 | 
			
		||||
_PROTOTYPE(void check, (char *s, struct dirstruct *dp1, int ent1, char *new));
 | 
			
		||||
_PROTOTYPE(void usage, (void));
 | 
			
		||||
 | 
			
		||||
int main(argc, argv)
 | 
			
		||||
int argc;
 | 
			
		||||
char *argv[];
 | 
			
		||||
{
 | 
			
		||||
  char *p;
 | 
			
		||||
 | 
			
		||||
  if (argc < 3 || argc > 4) usage();
 | 
			
		||||
  p = argv[1];
 | 
			
		||||
  if (argc == 4) {
 | 
			
		||||
	if (*p != '-') usage();
 | 
			
		||||
	p++;
 | 
			
		||||
	if (*p == '\0') usage();
 | 
			
		||||
	while (*p) {
 | 
			
		||||
		if (*p == 'c') changes++;
 | 
			
		||||
		if (*p == 'v') verbose++;
 | 
			
		||||
		if (*p != 'c' && *p != 'v') usage();
 | 
			
		||||
		p++;
 | 
			
		||||
	}
 | 
			
		||||
  }
 | 
			
		||||
  if (argc == 3)
 | 
			
		||||
	compare(argv[1], argv[2]);
 | 
			
		||||
  else
 | 
			
		||||
	compare(argv[2], argv[3]);
 | 
			
		||||
 | 
			
		||||
  return(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void compare(old, new)
 | 
			
		||||
char *old, *new;
 | 
			
		||||
{
 | 
			
		||||
/* This is the main comparision routine.  It gets two path names as arguments
 | 
			
		||||
 * and stats them both.  Depending on the results, it calls other routines
 | 
			
		||||
 * to compare directories or files.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
  int type1, type2;
 | 
			
		||||
 | 
			
		||||
  if (stat(new, &stat1) < 0) {
 | 
			
		||||
	/* The new file does not exist. */
 | 
			
		||||
	if (changes == 0)
 | 
			
		||||
		fprintf(stderr, "Cannot stat: %s\n", new);
 | 
			
		||||
	else
 | 
			
		||||
		printf("%s\n", new);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
  if (stat(old, &stat2) < 0) {
 | 
			
		||||
	/* The old file does not exist. */
 | 
			
		||||
	if (changes == 0) 
 | 
			
		||||
		fprintf(stderr, "Missing file: %s\n", old);
 | 
			
		||||
	else
 | 
			
		||||
		printf("%s\n", new);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Examine the types of the files. */
 | 
			
		||||
  type1 = stat1.st_mode & S_IFMT;
 | 
			
		||||
  type2 = stat2.st_mode & S_IFMT;
 | 
			
		||||
  if (type1 != type2) {
 | 
			
		||||
	fprintf(stderr, "Type diff: %s and %s\n", new, old);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* The types are the same. */
 | 
			
		||||
  switch (type1) {
 | 
			
		||||
      case S_IFREG:	regular(old, new);	break;
 | 
			
		||||
      case S_IFDIR:	directory(old, new);	break;
 | 
			
		||||
      case S_IFCHR:	break;
 | 
			
		||||
      case S_IFBLK:	break;
 | 
			
		||||
      default:		fprintf(stderr, "Unknown file type %o\n", type1);
 | 
			
		||||
  }
 | 
			
		||||
  return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void regular(old, new)
 | 
			
		||||
char *old, *new;
 | 
			
		||||
{
 | 
			
		||||
/* Compare to regular files.  If they are different, complain. */
 | 
			
		||||
 | 
			
		||||
  int fd1, fd2, n1, n2;
 | 
			
		||||
  unsigned bytes;
 | 
			
		||||
  long count;
 | 
			
		||||
 | 
			
		||||
  if (stat1.st_size != stat2.st_size) {
 | 
			
		||||
	if (changes == 0)
 | 
			
		||||
		printf("Size diff: %s and %s\n", new, old);
 | 
			
		||||
	else
 | 
			
		||||
		printf("%s\n", new);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* The sizes are the same.  We actually have to read the files now. */
 | 
			
		||||
  fd1 = open(new, O_RDONLY);
 | 
			
		||||
  if (fd1 < 0) {
 | 
			
		||||
	fprintf(stderr, "Cannot open %s for reading\n", new);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
  fd2 = open(old, O_RDONLY);
 | 
			
		||||
  if (fd2 < 0) {
 | 
			
		||||
	fprintf(stderr, "Cannot open %s for reading\n", old);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
  count = stat1.st_size;
 | 
			
		||||
  while (count > 0L) {
 | 
			
		||||
	bytes = (unsigned) (count > BUFSIZE ? BUFSIZE : count);	/* rd count */
 | 
			
		||||
	n1 = read(fd1, buf1, bytes);
 | 
			
		||||
	n2 = read(fd2, buf2, bytes);
 | 
			
		||||
	if (n1 != n2) {
 | 
			
		||||
		if (changes == 0)
 | 
			
		||||
			printf("Length diff: %s and %s\n", new, old);
 | 
			
		||||
		else
 | 
			
		||||
			printf("%s\n", new);
 | 
			
		||||
		close(fd1);
 | 
			
		||||
		close(fd2);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Compare the buffers. */
 | 
			
		||||
	if (memcmp((void *) buf1, (void *) buf2, (size_t) n1) != 0) {
 | 
			
		||||
		if (changes == 0)
 | 
			
		||||
			printf("File diff: %s and %s\n", new, old);
 | 
			
		||||
		else
 | 
			
		||||
			printf("%s\n", new);
 | 
			
		||||
		close(fd1);
 | 
			
		||||
		close(fd2);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	count -= n1;
 | 
			
		||||
  }
 | 
			
		||||
  close(fd1);
 | 
			
		||||
  close(fd2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void directory(old, new)
 | 
			
		||||
char *old, *new;
 | 
			
		||||
{
 | 
			
		||||
/* Recursively compare two directories by reading them and comparing their
 | 
			
		||||
 * contents.  The order of the entries need not be the same.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
  int fd1, fd2, n1, n2, ent1, ent2, i, used1 = 0, used2 = 0;
 | 
			
		||||
  char *dir1buf, *dir2buf;
 | 
			
		||||
  char name1buf[MAXPATH], name2buf[MAXPATH];
 | 
			
		||||
  struct dirstruct *dp1, *dp2;
 | 
			
		||||
  unsigned dir1bytes, dir2bytes;
 | 
			
		||||
 | 
			
		||||
  /* Allocate space to read in the directories */
 | 
			
		||||
  dir1bytes = (unsigned) stat1.st_size;
 | 
			
		||||
  dir1buf = (char *)malloc((size_t)dir1bytes);
 | 
			
		||||
  if (dir1buf == 0) {
 | 
			
		||||
	fprintf(stderr, "Cannot process directory %s: out of memory\n", new);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
  dir2bytes = (unsigned) stat2.st_size;
 | 
			
		||||
  dir2buf = (char *)malloc((size_t)dir2bytes);
 | 
			
		||||
  if (dir2buf == 0) {
 | 
			
		||||
	fprintf(stderr, "Cannot process directory %s: out of memory\n", old);
 | 
			
		||||
	free(dir1buf);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Read in the directories. */
 | 
			
		||||
  fd1 = open(new, O_RDONLY);
 | 
			
		||||
  if (fd1 > 0) n1 = read(fd1, dir1buf, dir1bytes);
 | 
			
		||||
  if (fd1 < 0 || n1 != dir1bytes) {
 | 
			
		||||
	fprintf(stderr, "Cannot read directory %s\n", new);
 | 
			
		||||
	free(dir1buf);
 | 
			
		||||
	free(dir2buf);
 | 
			
		||||
	if (fd1 > 0) close(fd1);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
  close(fd1);
 | 
			
		||||
 | 
			
		||||
  fd2 = open(old, O_RDONLY);
 | 
			
		||||
  if (fd2 > 0) n2 = read(fd2, dir2buf, dir2bytes);
 | 
			
		||||
  if (fd2 < 0 || n2 != dir2bytes) {
 | 
			
		||||
	fprintf(stderr, "Cannot read directory %s\n", old);
 | 
			
		||||
	free(dir1buf);
 | 
			
		||||
	free(dir2buf);
 | 
			
		||||
	close(fd1);
 | 
			
		||||
	if (fd2 > 0) close(fd2);
 | 
			
		||||
	return;
 | 
			
		||||
  }
 | 
			
		||||
  close(fd2);
 | 
			
		||||
 | 
			
		||||
  /* Linearly search directories */
 | 
			
		||||
  ent1 = dir1bytes / sizeof(struct dirstruct);
 | 
			
		||||
  dp1 = (struct dirstruct *) dir1buf;
 | 
			
		||||
  for (i = 0; i < ent1; i++) {
 | 
			
		||||
	if (dp1->inum != 0) used1++;
 | 
			
		||||
	dp1++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ent2 = dir2bytes / sizeof(struct dirstruct);
 | 
			
		||||
  dp2 = (struct dirstruct *) dir2buf;
 | 
			
		||||
  for (i = 0; i < ent2; i++) {
 | 
			
		||||
	if (dp2->inum != 0) used2++;
 | 
			
		||||
	dp2++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (verbose) printf("Directory %s: %d entries\n", new, used1);
 | 
			
		||||
 | 
			
		||||
  /* Check to see if any entries in dir2 are missing from dir1. */
 | 
			
		||||
  dp1 = (struct dirstruct *) dir1buf;
 | 
			
		||||
  dp2 = (struct dirstruct *) dir2buf;
 | 
			
		||||
  for (i = 0; i < ent2; i++) {
 | 
			
		||||
	if (dp2->inum == 0 || strcmp(dp2->fname, ".") == 0 ||
 | 
			
		||||
					    strcmp(dp2->fname, "..") == 0) {
 | 
			
		||||
		dp2++;
 | 
			
		||||
		continue;
 | 
			
		||||
	}
 | 
			
		||||
	check(dp2->fname, dp1, ent1, new);
 | 
			
		||||
	dp2++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Recursively process all the entries in dir1. */
 | 
			
		||||
  dp1 = (struct dirstruct *) dir1buf;
 | 
			
		||||
  for (i = 0; i < ent1; i++) {
 | 
			
		||||
	if (dp1->inum == 0 || strcmp(dp1->fname, ".") == 0 ||
 | 
			
		||||
	    strcmp(dp1->fname, "..") == 0) {
 | 
			
		||||
		dp1++;
 | 
			
		||||
		continue;
 | 
			
		||||
	}
 | 
			
		||||
	if (strlen(new) + DIRENTLEN >= MAXPATH) {
 | 
			
		||||
		fprintf(stderr, "Path too long: %s\n", new);
 | 
			
		||||
		free(dir1buf);
 | 
			
		||||
		free(dir2buf);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (strlen(old) + DIRENTLEN >= MAXPATH) {
 | 
			
		||||
		fprintf(stderr, "Path too long: %s\n", old);
 | 
			
		||||
		free(dir1buf);
 | 
			
		||||
		free(dir2buf);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	strcpy(name1buf, old);
 | 
			
		||||
	strcat(name1buf, "/");
 | 
			
		||||
	strncat(name1buf, dp1->fname, (size_t)DIRENTLEN);
 | 
			
		||||
	strcpy(name2buf, new);
 | 
			
		||||
	strcat(name2buf, "/");
 | 
			
		||||
	strncat(name2buf, dp1->fname, (size_t)DIRENTLEN);
 | 
			
		||||
 | 
			
		||||
	/* Here is the recursive call to process an entry. */
 | 
			
		||||
	compare(name1buf, name2buf);	/* recursive call */
 | 
			
		||||
	dp1++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  free(dir1buf);
 | 
			
		||||
  free(dir2buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void check(s, dp1, ent1, new)
 | 
			
		||||
char *s;
 | 
			
		||||
struct dirstruct *dp1;
 | 
			
		||||
int ent1;
 | 
			
		||||
char *new;
 | 
			
		||||
{
 | 
			
		||||
/* See if the file name 's' is present in the directory 'dirbuf'. */
 | 
			
		||||
  int i;
 | 
			
		||||
  char file[DIRENTLEN+1];
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < ent1; i++) {
 | 
			
		||||
	if (strncmp(dp1->fname, s, (size_t)DIRENTLEN) == 0) return;
 | 
			
		||||
	dp1++;
 | 
			
		||||
  }
 | 
			
		||||
  if (changes == 0) {
 | 
			
		||||
	strncpy(file, s, DIRENTLEN);
 | 
			
		||||
	file[DIRENTLEN] = '\0';
 | 
			
		||||
	printf("Missing file: %s/%s\n", new, file);
 | 
			
		||||
  }
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usage()
 | 
			
		||||
{
 | 
			
		||||
  printf("Usage: treecmp [-cv] old_dir new_dir\n");
 | 
			
		||||
  exit(1);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user