#ifndef NEW_UNUSED static int err_fail = 0 ; /* if an open or unlink error occurs */ static int diff_no = 0 ; /* for scs & msdos was struct _iobuf *err_fd ; now with 486 as well, is */ FILE *err_fd ; #else /* NEW_UNUSED */ static int success_exit_count = 0 ; static FILE *err_fd ; /* scs & msdos accept struct _iobuf *err_fd ; 486 doesnt */ static FLAG mail_f = 0 ; /* 1 if comparing email or news items ie dont start compare till after blank line */ static FLAG delete_f = 0 ; /* 1 to delete first of 2 equal files */ static FLAG suppress_f = 0 ; /* 1 to silence complaints of absent reference files (when trying to delete duplicate trees) */ static FLAG verbose_f = 0 ; /* 1 for verbose commentary */ #endif /* NEW_UNUSED */ #ifndef NEW_UNUSED main(argc, argv) int argc; char **argv; #else /* NEW_UNUSED */ /* return 1 if compares equal, -1 on error, 0 if different content */ static int cmp_file(name_rm_p,name_ref_p) char *name_rm_p ; char *name_ref_p ; #endif /* NEW_UNUSED */ { #ifndef NEW_UNUSED int ARGC; #else /* NEW_UNUSED */ #define BUF_SIZE 0x2000 int buf_size = BUF_SIZE ; char buf_file_rm[BUF_SIZE] ; /* buffer of file that may be deleted */ char buf_file_ref[BUF_SIZE]; /* reference buffer */ #endif /* NEW_UNUSED */ long letter, lines, bytes ; /* line & byte count */ #ifdef NEW_UNUSED int length_rm, length_ref, buf_len; FD file_rm ; /* file to compare & possibly rm */ struct stat rm_stat ; /* stat() & lstat() of file that may be removed */ char *pointer_rm, *pointer_ref; #endif /* NEW_UNUSED */ #ifndef NEW_UNUSED ARGV = argv ; #ifdef VSL /* { */ #include "../../include/vsl.h" #endif /* } */ ARGC = argc; err_fd = stderr ; for(argv++,argc--; argc ; ) #else /* NEW_UNUSED */ if (pipe_f) #endif /* NEW_UNUSED */ #else /* NEW_UNUSED */ file_ref = fileno(stdin) ; #ifdef MSDOS /* { */ /* JJLATER For Msdos: I dont know whether stdin is already open in binary mode, or whether something extra should be done here */ #endif /* } */ #endif /* NEW_UNUSED */ } #ifndef NEW_UNUSED if ( (argc < 1) || ((argc == 1 ) && (pipe_f == 0)) || ((argc > 1 ) && pipe_f )) syntax() ; if (!pipe_f) { /* scs used #define REF_DIR ARGV[ARGC-1] but when running on 486 it blows up !, acceptable to both is: #define REF_DIR ( * (ARGV + ARGC - 1 ) ) */ if (strequ(REF_DIR,".")) fprintf(err_fd, "%s: Warning: %s\n%s\n", *ARGV, "Comparison using \".\" as reference directory,", "is likely to result in equality.") ; /* not guaranteed to be an error, however, as "cmpd -d ../something ." might be designed to zap the spare copy in the dir. above */ } else if ( argc > 2 ) #else /* NEW_UNUSED */ else { if (stat(*argv,STRADR rm_stat)) #endif /* NEW_UNUSED */ { #ifndef NEW_UNUSED fprintf(err_fd, "%s: Error: %s should be a directory.\n", *ARGV, REF_DIR ); syntax() ; #else /* NEW_UNUSED */ fprintf(err_fd, "%s: Warning, cannot stat %s.\n", *ARGV,*argv); return(-1); #endif /* NEW_UNUSED */ } } #ifndef NEW_UNUSED while (argc-- >= (2 - pipe_f)) { if (pipe_f) #else /* NEW_UNUSED */ if (stat(ref_file,STRADR ref_stat)) #endif /* NEW_UNUSED */ { #ifndef NEW_UNUSED file_ref = fileno(stdin) ; #ifdef MSDOS /* { */ /* JJLATER For Msdos: I dont know whether stdin is already open in binary mode, or whether something extra should be done here */ #endif /* } */ #else /* NEW_UNUSED */ if (!suppress_f) fprintf(err_fd, "%s: Error, cannot stat %s.\n", *ARGV, ref_file) ; err_fail = 1 ; success_exit_count++ ; return(-1); #endif /* NEW_UNUSED */ } #ifndef NEW_UNUSED else { if (stat(*argv,STRADR rm_stat)) #else /* NEW_UNUSED */ /* avoid deleting a file that is named by 2 different paths, but has only one link, such as cmp -d fred ../freds_dir/fred */ if ( (rm_stat.st_dev == ref_stat.st_dev) /* device (dev_t) */ && (rm_stat.st_ino == ref_stat.st_ino) /* inode (ino_t) */ #ifndef MSDOS /* { */ && (rm_stat.st_nlink == 1 ) #endif /* } */ ) { /* both names point to same inode */ #ifdef SYM_LINKS_AVAIL /* { */ /* see if first name is just a symbolic link, if so allow deletion */ if (lstat(*argv,STRADR rm_stat)) #endif /* NEW_UNUSED */ { fprintf(err_fd, #ifndef NEW_UNUSED "%s: Warning, %s %s\n", *ARGV, txt_cant_stat, *argv); err_fail = 1 ; diff_no++ ; argv++ ; continue ; } /* assemble name of reference file */ (void) strcpy(name_ref, REF_DIR ); if (is_dir) { (void)strcat(name_ref,"/"); (void)strcat(name_ref,*argv); #else /* NEW_UNUSED */ "%s: Error, cannot lstat %s.\n", *ARGV, *argv) ; perror(*ARGV); return(0) ; #endif /* NEW_UNUSED */ } #ifndef NEW_UNUSED #ifndef MSDOS /* { */ /* Avoid deleting a single file pointed to by different paths, such as fred & ../freds_dir/fred, whether by direct naming or by symbolic link. Compare device major minor + inode numbers here, if all the same refuse to delete! */ if (delete_f) { /* avoid deleting a file that is named by 2 different paths, but has only one link, such as cmp -d fred ../freds_dir/fred */ if (stat(name_ref,STRADR ref_stat)) { if (!suppress_f) fprintf(err_fd, "%s: Error, %s %s\n", *ARGV, txt_cant_stat, name_ref) ; err_fail = 1 ; diff_no++ ; argv++ ; continue ; } if ( (rm_stat.st_dev == ref_stat.st_dev) /* device (dev_t) */ && (rm_stat.st_ino == ref_stat.st_ino) /* inode (ino_t) */ && (rm_stat.st_nlink == 1 ) ) { /* both names point to same inode */ #ifdef SYM_LINKS_AVAIL /* { */ /* see if first name is just a symbolic link, if so allow deletion */ if (lstat(*argv,STRADR rm_stat)) { fprintf(err_fd, "%s: Error, cannot lstat %s.\n", *ARGV, *argv) ; /* txt_cant_stat */ perror(*ARGV); err_fail = 1 ; diff_no++ ; argv++ ; continue ; } #endif /* } */ if ( #ifdef SYM_LINKS_AVAIL /* { */ (rm_stat.st_mode & S_IFMT) != S_IFLNK /* IFLNK == sym link */ #else /* NEW_UNUSED */ #endif /* } */ if ( #ifdef SYM_LINKS_AVAIL /* { */ (rm_stat.st_mode & S_IFMT) != S_IFLNK /* IFLNK == sym link */ #endif /* NEW_UNUSED */ #else /* }{ */ #ifndef NEW_UNUSED /* no symbolic linked files on non SYM_LINKS_AVAIL unix */ 1 #else /* NEW_UNUSED */ /* no symbolic linked files on non SYM_LINKS_AVAIL unix */ 1 #endif /* NEW_UNUSED */ #endif /* } */ #ifndef NEW_UNUSED ) { /* Not an innocuous symbolic link, so avoid deleting. */ fprintf(err_fd, #ifdef SYM_LINKS_AVAIL /* { */ "%s: %s %s & %s %s,\n\t%s, & %s %s; %s\n", #else /* NEW_UNUSED */ ) { /* Not an innocuous symbolic link, so avoid deleting. */ fprintf(err_fd, #ifdef SYM_LINKS_AVAIL /* { */ "%s: %s %s & %s %s,\n\t%s, & %s %s; %s\n", #endif /* NEW_UNUSED */ #else /* }{ */ #ifndef NEW_UNUSED "%s: %s %s & %s %s,\n\t%s; %s\n", #else /* NEW_UNUSED */ "%s: %s %s & %s %s,\n\t%s; %s\n", #endif /* NEW_UNUSED */ #endif /* } */ #ifndef NEW_UNUSED *ARGV, "Error: ", *argv, name_ref, "share same device (major & minor) & inode ", "link count is 1", #ifdef SYM_LINKS_AVAIL /* { */ *argv, "isn't a symbolic link", #endif /* } */ "Skipping." ); diff_no++ ; argv++ ; continue ; } } #else /* NEW_UNUSED */ *ARGV, "Error: ", *argv, ref_file, "share same device (major & minor) & inode ", "link count is 1", #ifdef SYM_LINKS_AVAIL /* { */ *argv, "isn't a symbolic link", #endif /* } */ "Skipping." ); return(-1); #endif /* NEW_UNUSED */ } #ifdef NEW_UNUSED } #endif /* NEW_UNUSED */ #endif /* } */ #ifndef NEW_UNUSED if ((file_ref = open(name_ref,O_RDONLY #else /* NEW_UNUSED */ if ((file_ref = open(ref_file,O_RDONLY #endif /* NEW_UNUSED */ #ifdef MSDOS /* { */ #ifndef NEW_UNUSED | O_BINARY #else /* NEW_UNUSED */ | O_BINARY #endif /* NEW_UNUSED */ #endif /* } */ #ifndef NEW_UNUSED )) == -1) { fprintf(err_fd,"%s: Cannot open %s\n", *ARGV,name_ref); (void) close(file_rm) ; err_fail = 1 ; diff_no++ ; argv++ ; continue ; } } /* now check if we are comparing device with device */ if (((rm_stat.st_mode & S_IFMT) != S_IFREG ) && ((rm_stat.st_mode & S_IFMT) == (ref_stat.st_mode & S_IFMT)) && (rm_stat.st_rdev == ref_stat.st_rdev) ) #else /* NEW_UNUSED */ )) == -1) #endif /* NEW_UNUSED */ { #ifndef NEW_UNUSED /* JJ add code here, do something about comparing 2 sym links, & a sym link to a fifo */ /* 386bsd values: S_IFMT 0170000 type of file S_IFIFO 0010000 named pipe (fifo) S_IFCHR 0020000 character special S_IFDIR 0040000 directory S_IFBLK 0060000 block special S_IFREG 0100000 regular S_IFLNK 0120000 symbolic link S_IFSOCK 0140000 socket */ #else /* NEW_UNUSED */ fprintf(err_fd,"%s: Cannot open %s\n", *ARGV,ref_file); (void) close(file_rm) ; return(-1) ; #endif /* NEW_UNUSED */ } #ifdef NEW_UNUSED } /* Are we to compare regular files with link count == 1, or exotica such as: named pipe (fifo), character or block special, directory, symbolic link, socket, regular files with link count > 1 */ #ifndef MSDOS /* { */ if ((rm_stat.st_mode & S_IFMT) != S_IFREG ) { if (((rm_stat.st_mode & S_IFMT) == (ref_stat.st_mode & S_IFMT)) && (rm_stat.st_rdev == ref_stat.st_rdev) ) /* JJ add code here, do something about comparing 2 sym links, & a sym link to a fifo */ else #endif /* } */ { #endif /* NEW_UNUSED */ if ((file_rm = open(*argv,O_RDONLY #ifdef MSDOS /* { */ | O_BINARY #endif /* } */ )) == -1) { fprintf(err_fd,"%s: Cannot open %s\n",*ARGV,*argv); #ifndef NEW_UNUSED err_fail = 1 ; diff_no++ ; argv++ ; continue ; #else /* NEW_UNUSED */ return(-1) ; #endif /* NEW_UNUSED */ } letter = lines = bytes = 1 ; if (mail_f) { #ifndef NEW_UNUSED skip(file_ref,name_ref) ; skip(file_rm, (pipe_f) ? "pipe input" :*argv); #else /* NEW_UNUSED */ (void) skip(file_ref,ref_file)); (void) skip(file_rm, (pipe_f) ? "pipe input" :*argv) ; #endif /* NEW_UNUSED */ } for (;;) { #ifndef NEW_UNUSED if ( (( length_ref = read(file_ref,buf_file_ref,bufsize)) < 0) || ((length_rm = read(file_rm,buf_file_rm, (length_ref == 0) ? bufsize : length_ref /* not just bufsize as read on a pipe cannot return more than 4K */ )) < 0) ) #else /* NEW_UNUSED */ if ( (( length_ref = read(file_ref,buf_file_ref,buf_size)) < 0) || ((length_rm = read(file_rm,buf_file_rm, (length_ref == 0) ? buf_size : length_ref /* not just buf_size as read on a pipe cannot return more than 4K */ )) < 0) ) #endif /* NEW_UNUSED */ { #ifndef NEW_UNUSED fprintf(err_fd,"%s: Read error on ", *ARGV); #else /* NEW_UNUSED */ fprintf(err_fd,"%s: Read error on ", *ARGV); #endif /* NEW_UNUSED */ if (length_rm < 0 ) fprintf(err_fd,"%s.\n", #ifndef NEW_UNUSED (pipe_f) ? "pipe input" :*argv); #else /* NEW_UNUSED */ (pipe_f) ? "pipe input" : *argv); #endif /* NEW_UNUSED */ else { #ifndef NEW_UNUSED if (is_dir) fprintf(err_fd,"%s/%s.\n", REF_DIR , *argv); #else /* NEW_UNUSED */ if (is_dir) fprintf(err_fd, "%s/%s.\n", REFERENCE , *argv); #endif /* NEW_UNUSED */ else fprintf(err_fd,"%s.\n",*argv); } #ifndef NEW_UNUSED err_fail = 1 ; diff_no++ ; break ; #else /* NEW_UNUSED */ return(-1) ; #endif /* NEW_UNUSED */ } if ((length_rm == 0) && (length_ref == 0)) { if (verbose_f) { if (is_dir ) printf("%s ",*argv); #ifndef NEW_UNUSED printf( delete_f ? "Deleted.\n": "Same.\n"); #else /* NEW_UNUSED */ printf( delete_f ? "Deleted.\n": "Same.\n"); #endif /* NEW_UNUSED */ } if (delete_f && unlink(*argv)) #ifndef NEW_UNUSED { perror(*ARGV); diff_no++ ; err_fail = 1 ; } #else /* NEW_UNUSED */ { perror(*ARGV); return(-1) ; } #endif /* NEW_UNUSED */ break ; } #ifndef NEW_UNUSED buf_len = (length_rm < length_ref ) ? length_rm : length_ref ; pointer_rm = buf_file_rm; pointer_ref = buf_file_ref ; #else /* NEW_UNUSED */ buf_len = (length_rm < length_ref ) ? length_rm : length_ref ; pointer_rm = buf_file_rm; pointer_ref = buf_file_ref ; #endif /* NEW_UNUSED */ while (buf_len && (*pointer_rm == *pointer_ref) ) { bytes++ ; letter++ ; if ((*pointer_rm & 0xFF) == '\n') { letter = 1 ; lines++ ; } buf_len--; pointer_rm++; pointer_ref++ ; } #ifndef NEW_UNUSED if ((buf_len == 0) && (length_rm == length_ref)) #else /* NEW_UNUSED */ if ((buf_len == 0) && (length_rm == length_ref)) #endif /* NEW_UNUSED */ continue ; if (!delete_f || verbose_f) { if (is_dir) printf("%s ",*argv); printf( #ifndef NEW_UNUSED "Different: char %ld in line %ld, (byte %ld).\n", #else /* NEW_UNUSED */ "Different: char %ld in line %ld, (byte %ld).\n", #endif /* NEW_UNUSED */ letter,lines,bytes); #ifdef NEW_UNUSED return(0) ; #endif /* NEW_UNUSED */ } #ifndef NEW_UNUSED diff_no++ ; break ; #else /* NEW_UNUSED */ return(-1) ; #endif /* NEW_UNUSED */ } if (!pipe_f) (void) close(file_ref) ; (void) close(file_rm); #ifndef NEW_UNUSED argv++ ; #else /* NEW_UNUSED */ } } struct stat last_stat ; /* stat() of reference file/directory */ char ref_file[1024]; /* comparison reference file */ int ret ; FLAG err_fail = 0 ; /* if an open or unlink error occurs */ if (stat(REFERENCE,STRADR last_stat)) { fprintf(err_fd, "%s: Error, cannot stat %s.\n", *ARGV,REFERENCE ); syntax(-1) ; } if (last_stat.st_mode & S_IFDIR) { is_dir = 1; /* Detect & warn of construct such as "cmp fred jim ." (because == "cmp fred ./fred" && "cmp jim ./jim" == TRUE (always!) */ if (strequ(REFERENCE,".")) { fprintf(err_fd, "%s: Warning: %s\n%s\n", *ARGV, "Comparison using \".\" as reference directory,", "will always result in equality.") ; if (delete_f) { fprintf(err_fd, "So aborting\n"); exit(-1); } } } else if ( argc > 2 ) { fprintf(err_fd, "%s: Error: %s should be a directory.\n", *ARGV, REFERENCE ); syntax(-1) ; } } while (argc-- >= (2 - pipe_f)) { if (!pipe_f) { /* assemble name of reference file */ (void) strcpy(ref_file, REFERENCE ); if (is_dir) { (void)strcat(ref_file,"/"); (void)strcat(ref_file,*argv); } } ret = cmp_file(*argv++,ref_file) ; if ( ret > 0 ) success_exit_count++ ; else if ( ret < 0 ) err_fail = 1 ; #endif /* NEW_UNUSED */ } #ifndef NEW_UNUSED if (err_fail) exit(-diff_no) ; else exit(diff_no) ; #else /* NEW_UNUSED */ if (err_fail) exit(-1) ; else exit(success_exit_count) ; #endif /* NEW_UNUSED */ }