Remove treecmp utility (Bug#310, reported by John Peace)
This commit is contained in:
parent
2ac8124914
commit
bc029d0bc6
2 changed files with 0 additions and 336 deletions
|
@ -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…
Reference in a new issue