00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <sys/types.h>
00020 #include <sys/stat.h>
00021 #include <fcntl.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026
00027 #define BUFSIZE 4096
00028 #define MAXPATH 128
00029 #define DIRENTLEN 14
00030
00031 struct dirstruct {
00032 ino_t inum;
00033 char fname[DIRENTLEN];
00034 };
00035
00036 struct stat stat1, stat2;
00037
00038 char buf1[BUFSIZE];
00039 char buf2[BUFSIZE];
00040
00041 int changes;
00042 int verbose;
00043
00044 _PROTOTYPE(int main, (int argc, char **argv));
00045 _PROTOTYPE(void compare, (char *old, char *new));
00046 _PROTOTYPE(void regular, (char *old, char *new));
00047 _PROTOTYPE(void directory, (char *old, char *new));
00048 _PROTOTYPE(void check, (char *s, struct dirstruct *dp1, int ent1, char *new));
00049 _PROTOTYPE(void usage, (void));
00050
00051 int main(argc, argv)
00052 int argc;
00053 char *argv[];
00054 {
00055 char *p;
00056
00057 if (argc < 3 || argc > 4) usage();
00058 p = argv[1];
00059 if (argc == 4) {
00060 if (*p != '-') usage();
00061 p++;
00062 if (*p == '\0') usage();
00063 while (*p) {
00064 if (*p == 'c') changes++;
00065 if (*p == 'v') verbose++;
00066 if (*p != 'c' && *p != 'v') usage();
00067 p++;
00068 }
00069 }
00070 if (argc == 3)
00071 compare(argv[1], argv[2]);
00072 else
00073 compare(argv[2], argv[3]);
00074
00075 return(0);
00076 }
00077
00078 void compare(old, new)
00079 char *old, *new;
00080 {
00081
00082
00083
00084
00085
00086 int type1, type2;
00087
00088 if (stat(new, &stat1) < 0) {
00089
00090 if (changes == 0)
00091 fprintf(stderr, "Cannot stat: %s\n", new);
00092 else
00093 printf("%s\n", new);
00094 return;
00095 }
00096 if (stat(old, &stat2) < 0) {
00097
00098 if (changes == 0)
00099 fprintf(stderr, "Missing file: %s\n", old);
00100 else
00101 printf("%s\n", new);
00102 return;
00103 }
00104
00105
00106 type1 = stat1.st_mode & S_IFMT;
00107 type2 = stat2.st_mode & S_IFMT;
00108 if (type1 != type2) {
00109 fprintf(stderr, "Type diff: %s and %s\n", new, old);
00110 return;
00111 }
00112
00113
00114 switch (type1) {
00115 case S_IFREG: regular(old, new); break;
00116 case S_IFDIR: directory(old, new); break;
00117 case S_IFCHR: break;
00118 case S_IFBLK: break;
00119 default: fprintf(stderr, "Unknown file type %o\n", type1);
00120 }
00121 return;
00122 }
00123
00124 void regular(old, new)
00125 char *old, *new;
00126 {
00127
00128
00129 int fd1, fd2, n1, n2;
00130 unsigned bytes;
00131 long count;
00132
00133 if (stat1.st_size != stat2.st_size) {
00134 if (changes == 0)
00135 printf("Size diff: %s and %s\n", new, old);
00136 else
00137 printf("%s\n", new);
00138 return;
00139 }
00140
00141
00142 fd1 = open(new, O_RDONLY);
00143 if (fd1 < 0) {
00144 fprintf(stderr, "Cannot open %s for reading\n", new);
00145 return;
00146 }
00147 fd2 = open(old, O_RDONLY);
00148 if (fd2 < 0) {
00149 fprintf(stderr, "Cannot open %s for reading\n", old);
00150 return;
00151 }
00152 count = stat1.st_size;
00153 while (count > 0L) {
00154 bytes = (unsigned) (count > BUFSIZE ? BUFSIZE : count);
00155 n1 = read(fd1, buf1, bytes);
00156 n2 = read(fd2, buf2, bytes);
00157 if (n1 != n2) {
00158 if (changes == 0)
00159 printf("Length diff: %s and %s\n", new, old);
00160 else
00161 printf("%s\n", new);
00162 close(fd1);
00163 close(fd2);
00164 return;
00165 }
00166
00167
00168 if (memcmp((void *) buf1, (void *) buf2, (size_t) n1) != 0) {
00169 if (changes == 0)
00170 printf("File diff: %s and %s\n", new, old);
00171 else
00172 printf("%s\n", new);
00173 close(fd1);
00174 close(fd2);
00175 return;
00176 }
00177 count -= n1;
00178 }
00179 close(fd1);
00180 close(fd2);
00181 }
00182
00183 void directory(old, new)
00184 char *old, *new;
00185 {
00186
00187
00188
00189
00190 int fd1, fd2, n1, n2, ent1, ent2, i, used1 = 0, used2 = 0;
00191 char *dir1buf, *dir2buf;
00192 char name1buf[MAXPATH], name2buf[MAXPATH];
00193 struct dirstruct *dp1, *dp2;
00194 unsigned dir1bytes, dir2bytes;
00195
00196
00197 dir1bytes = (unsigned) stat1.st_size;
00198 dir1buf = (char *)malloc((size_t)dir1bytes);
00199 if (dir1buf == 0) {
00200 fprintf(stderr, "Cannot process directory %s: out of memory\n", new);
00201 return;
00202 }
00203 dir2bytes = (unsigned) stat2.st_size;
00204 dir2buf = (char *)malloc((size_t)dir2bytes);
00205 if (dir2buf == 0) {
00206 fprintf(stderr, "Cannot process directory %s: out of memory\n", old);
00207 free(dir1buf);
00208 return;
00209 }
00210
00211
00212 fd1 = open(new, O_RDONLY);
00213 if (fd1 > 0) n1 = read(fd1, dir1buf, dir1bytes);
00214 if (fd1 < 0 || n1 != dir1bytes) {
00215 fprintf(stderr, "Cannot read directory %s\n", new);
00216 free(dir1buf);
00217 free(dir2buf);
00218 if (fd1 > 0) close(fd1);
00219 return;
00220 }
00221 close(fd1);
00222
00223 fd2 = open(old, O_RDONLY);
00224 if (fd2 > 0) n2 = read(fd2, dir2buf, dir2bytes);
00225 if (fd2 < 0 || n2 != dir2bytes) {
00226 fprintf(stderr, "Cannot read directory %s\n", old);
00227 free(dir1buf);
00228 free(dir2buf);
00229 close(fd1);
00230 if (fd2 > 0) close(fd2);
00231 return;
00232 }
00233 close(fd2);
00234
00235
00236 ent1 = dir1bytes / sizeof(struct dirstruct);
00237 dp1 = (struct dirstruct *) dir1buf;
00238 for (i = 0; i < ent1; i++) {
00239 if (dp1->inum != 0) used1++;
00240 dp1++;
00241 }
00242
00243 ent2 = dir2bytes / sizeof(struct dirstruct);
00244 dp2 = (struct dirstruct *) dir2buf;
00245 for (i = 0; i < ent2; i++) {
00246 if (dp2->inum != 0) used2++;
00247 dp2++;
00248 }
00249
00250 if (verbose) printf("Directory %s: %d entries\n", new, used1);
00251
00252
00253 dp1 = (struct dirstruct *) dir1buf;
00254 dp2 = (struct dirstruct *) dir2buf;
00255 for (i = 0; i < ent2; i++) {
00256 if (dp2->inum == 0 || strcmp(dp2->fname, ".") == 0 ||
00257 strcmp(dp2->fname, "..") == 0) {
00258 dp2++;
00259 continue;
00260 }
00261 check(dp2->fname, dp1, ent1, new);
00262 dp2++;
00263 }
00264
00265
00266 dp1 = (struct dirstruct *) dir1buf;
00267 for (i = 0; i < ent1; i++) {
00268 if (dp1->inum == 0 || strcmp(dp1->fname, ".") == 0 ||
00269 strcmp(dp1->fname, "..") == 0) {
00270 dp1++;
00271 continue;
00272 }
00273 if (strlen(new) + DIRENTLEN >= MAXPATH) {
00274 fprintf(stderr, "Path too long: %s\n", new);
00275 free(dir1buf);
00276 free(dir2buf);
00277 return;
00278 }
00279 if (strlen(old) + DIRENTLEN >= MAXPATH) {
00280 fprintf(stderr, "Path too long: %s\n", old);
00281 free(dir1buf);
00282 free(dir2buf);
00283 return;
00284 }
00285 strcpy(name1buf, old);
00286 strcat(name1buf, "/");
00287 strncat(name1buf, dp1->fname, (size_t)DIRENTLEN);
00288 strcpy(name2buf, new);
00289 strcat(name2buf, "/");
00290 strncat(name2buf, dp1->fname, (size_t)DIRENTLEN);
00291
00292
00293 compare(name1buf, name2buf);
00294 dp1++;
00295 }
00296
00297 free(dir1buf);
00298 free(dir2buf);
00299 }
00300
00301 void check(s, dp1, ent1, new)
00302 char *s;
00303 struct dirstruct *dp1;
00304 int ent1;
00305 char *new;
00306 {
00307
00308 int i;
00309 char file[DIRENTLEN+1];
00310
00311 for (i = 0; i < ent1; i++) {
00312 if (strncmp(dp1->fname, s, (size_t)DIRENTLEN) == 0) return;
00313 dp1++;
00314 }
00315 if (changes == 0) {
00316 strncpy(file, s, DIRENTLEN);
00317 file[DIRENTLEN] = '\0';
00318 printf("Missing file: %s/%s\n", new, file);
00319 }
00320
00321 }
00322
00323 void usage()
00324 {
00325 printf("Usage: treecmp [-cv] old_dir new_dir\n");
00326 exit(1);
00327 }