📄 remsync.c
字号:
fprintf(difffp, " d%03o %u %u\n", (unsigned) new->mode, (unsigned) new->uid, (unsigned) new->gid); if (vflag) fprintf(stderr, "mkdir %s\n", new->path); break; case F_FILE: path_init(&file); path_add(&file, tree); path_add(&file, new->path); if ((f= open(path_name(&file), O_RDONLY)) < 0) { report(path_name(&file)); path_drop(&file); fprintf(difffp, " ignore\n"); break; } fprintf(difffp, " %03o %u %u %lu %lu\n", (unsigned) new->mode, (unsigned) new->uid, (unsigned) new->gid, (unsigned long) new->size, (unsigned long) new->mtime); checkdiff(); if (!cat(f, new->size)) { int err= errno; report(path_name(&file)); fprintf(difffp, "old "); checkdiff(); print_name(difffp, err == EINVAL ? "File changed when copied" : strerror(err)); fputc('\n', difffp); checkdiff(); } else { if (vflag) { fprintf(stderr, "%s %s\n", old == nil ? "add" : old->mtime > new->mtime ? "restore" : "update", new->path); } } close(f); path_drop(&file); break; case F_BLK: case F_CHR: fprintf(difffp, " %c%03o %u %u %lx\n", new->type == F_BLK ? 'b' : 'c', (unsigned) new->mode, (unsigned) new->uid, (unsigned) new->gid, (unsigned long) new->rdev); if (vflag) fprintf(stderr, "mknod %s\n", new->path); break; case F_PIPE: fprintf(difffp, " p%03o %u %u\n", (unsigned) new->mode, (unsigned) new->uid, (unsigned) new->gid); if (vflag) fprintf(stderr, "mkfifo %s\n", new->path); break; case F_LINK: fprintf(difffp, " -> "); checkdiff(); (void) print_name(difffp, new->link); checkdiff(); fputc('\n', difffp); if (vflag) { fprintf(stderr, "ln -s %s %s\n", new->link, new->path); } break; } checkdiff();}void mkdifferences(void){ entry_t *remote; entry_t *local; remote= readstate(); local= traverse(); while (remote != nil || local != nil) { switch (compare(remote, local)) { case DELETE: /* Remove the remote file. */ delete(remote); remote->ignore= 1; remote= readstate(); break; case REPLACE: /* Replace the remote file with the local one. */ if (remote->type == F_FILE && local->type == F_FILE && !local->linked) { /* Don't overwrite, remove first. */ delete(remote); } /*FALL THROUGH*/ case COPY: /* Overwrite the remote file with the local one. */ add(remote, local); remote->ignore= 1; goto skip2; case SIMILAR: /* About the same, but the attributes need changing. */ change_modes(remote, local); goto skip2; case EQUAL: skip2: /* Skip two files. */ remote= readstate(); local= traverse(); break; case ADD: /* Add the local file. */ add(nil, local); local= traverse(); break; } } fprintf(difffp, "end\n"); fflush(difffp); checkdiff();}void apply_remove(pathname_t *pp)/* Remove an obsolete file. */{ struct stat st; if (lstat(path_name(pp), &st) < 0) { if (errno != ENOENT) report(path_name(pp)); return; } if (S_ISDIR(st.st_mode)) { /* Recursively delete directories. */ size_t len; namelist_t *entries; if ((entries= collect(path_name(pp))) == nil && errno != 0) { report(path_name(pp)); return; } len= path_length(pp); while (entries != nil) { path_add(pp, pop_name(&entries)); apply_remove(pp); path_trunc(pp, len); } if (rmdir(path_name(pp)) < 0) { report(path_name(pp)); return; } if (vflag) fprintf(stderr, "rmdir %s\n", path_name(pp)); } else { /* Some other type of file. */ if (unlink(path_name(pp)) < 0) { report(path_name(pp)); return; } if (vflag) fprintf(stderr, "rm %s\n", path_name(pp)); }}void apply_mkold(const char *file, const char *err)/* Make a file very old. (An error occurred when it was added.) */{ struct utimbuf utb; utb.actime= utb.modtime= 0; if (utime(file, &utb) < 0) { report(file); return; } fprintf(stderr, "made %s look old", file); fprintf(stderr, err == nil ? "\n" : " due to a remote problem: %s\n", err);}void apply_chmod(const char *file, mode_t mode, uid_t uid, gid_t gid, int talk)/* Change mode and ownership. */{ struct stat st; if (lstat(file, &st) < 0) { report(file); return; } if ((st.st_mode & 07777) != mode) { if (chmod(file, mode) < 0) { report(file); return; } if (vflag && talk) { fprintf(stderr, "chmod %03o %s\n", (unsigned) mode, file); } } if (st.st_uid != uid || st.st_gid != gid) { if (chown(file, uid, gid) < 0) { if (errno != EPERM) report(file); return; } if (vflag && talk) { fprintf(stderr, "chown %u:%u %s\n", (unsigned) uid, (unsigned) gid, file); } }}void apply_add(pathname_t *pp, entry_t *entry)/* Add or replace a file. */{ const char *file; off_t size; int f; unsigned char buf[1024 << sizeof(int)]; unsigned char *p; int c; int dirty; struct stat st; struct utimbuf utb; if (entry->ignore) return; if (lstat(path_name(pp), &st) >= 0 && (entry->type != F_FILE || !S_ISREG(st.st_mode))) { apply_remove(pp); } file= path_name(pp); switch (entry->type) { case F_DIR: if (mkdir(file, entry->mode) < 0) { report(file); return; } if (vflag) fprintf(stderr, "mkdir %s\n", file); break; case F_FILE: size= entry->size; f= -1; st.st_mode= 0; if (lstat(file, &st) < 0 || S_ISREG(st.st_mode)) { f= open(file, O_WRONLY | O_CREAT | O_TRUNC, entry->mode); if (f < 0) { (void) chmod(file, entry->mode | 0200); f= open(file, O_WRONLY | O_CREAT | O_TRUNC, entry->mode); } if (f < 0) { (void) unlink(file); f= open(file, O_WRONLY | O_CREAT | O_TRUNC, entry->mode); } if (f < 0) report(file); } dirty= (f >= 0); p= buf; while (size > 0 && (c= getc(difffp)) != EOF) { size--; *p++= c; if (p == arraylimit(buf) || size == 0) { if (f >= 0 && write(f, buf, p - buf) < 0) { report(file); close(f); f= -1; } p= buf; } } if (size > 0) { if (ferror(difffp)) report(diff_file); if (feof(difffp)) { fprintf(stderr, "remspec: %s: premature EOF\n", diff_file); } if (dirty) apply_mkold(file, nil); exit(1); } if (f < 0) { if (dirty) apply_mkold(file, nil); return; } close(f); if (vflag) { fprintf(stderr, st.st_mode == 0 ? "add %s\n" : entry->mtime >= st.st_mtime ? "update %s\n" : "restore %s\n", file); } utb.actime= time(nil); utb.modtime= entry->mtime; if (utime(file, &utb) < 0) report(file); break; case F_BLK: if (mknod(file, S_IFBLK | entry->mode, entry->rdev) < 0) { report(file); return; } if (vflag) { fprintf(stderr, "mknod %s b %d %d\n", file, major(entry->rdev), minor(entry->rdev)); } break; case F_CHR: if (mknod(file, S_IFCHR | entry->mode, entry->rdev) < 0) { report(file); return; } if (vflag) { fprintf(stderr, "mknod %s c %d %d\n", file, major(entry->rdev), minor(entry->rdev)); } break; case F_PIPE: if (mknod(file, S_IFIFO | entry->mode, 0) < 0) { report(file); return; } if (vflag) fprintf(stderr, "mknod %s p\n", file); break; case F_LINK: if (symlink(entry->link, file) < 0) { report(file); return; } if (vflag) fprintf(stderr, "ln -s %s %s\n", entry->link, file); return; } apply_chmod(file, entry->mode, entry->uid, entry->gid, 0);}void apply_link(const char *file, pathname_t *pp)/* Hard link *pp to file. */{ struct stat st1, st2; if (lstat(file, &st1) < 0) { report(file); return; } if (lstat(path_name(pp), &st2) >= 0) { if (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev) return; apply_remove(pp); if (lstat(path_name(pp), &st2) >= 0) return; } if (link(file, path_name(pp)) < 0) { fprintf(stderr, "remsync: ln %s %s: %s\n", file, path_name(pp), strerror(errno)); excode= 1; return; } if (vflag) fprintf(stderr, "ln %s %s\n", file, path_name(pp));}void diff_syntax(const char *line){ fprintf(stderr, "remsync: %s: syntax error on this line: %s\n", diff_file, line); exit(1);}void apply_differences(void)/* Update a tree to a list of differences derived from a remote tree. */{ char *line; char **argv; size_t argc; pathname_t path, link; size_t trunc; path_init(&path); path_init(&link); path_add(&path, tree); path_add(&link, tree); trunc= path_length(&path); while (!feof(difffp) && (line= read1line(difffp)) != nil) { splitline(line, &argv, &argc); if (argc == 0) diff_syntax(line); path_trunc(&path, trunc); if (strcmp(argv[0], "add") == 0) { entry_t entry; if (argc < 3) diff_syntax(line); path_add(&path, argv[1]); entry.ignore= (strcmp(argv[2], "ignore") == 0); if (!entry.ignore && !getattributes(&entry, argc - 2, argv + 2)) diff_syntax(line); apply_add(&path, &entry); } else if (strcmp(argv[0], "rm") == 0) { if (argc != 2) diff_syntax(line); path_add(&path, argv[1]); apply_remove(&path); } else if (strcmp(argv[0], "ln") == 0) { if (argc != 3) diff_syntax(line); path_trunc(&link, trunc); path_add(&link, argv[1]); path_add(&path, argv[2]); apply_link(path_name(&link), &path); } else if (strcmp(argv[0], "chmod") == 0) { if (argc != 5) diff_syntax(line); path_add(&path, argv[1]); apply_chmod(path_name(&path), strtoul(argv[2], nil, 010), strtoul(argv[3], nil, 10), strtoul(argv[4], nil, 10), 1); } else if (strcmp(argv[0], "old") == 0) { if (argc != 3) diff_syntax(line); path_add(&path, argv[1]); apply_mkold(path_name(&path), argv[2]); } else if (strcmp(argv[0], "end") == 0) { if (argc != 1) diff_syntax(line); break; } else { diff_syntax(line); } } checkdiff();}void usage(void){ fprintf(stderr, "Usage: remsync -sxv tree [state-file]\n"); fprintf(stderr, " remsync -duxvD tree [state-file [diff-file]]\n"); fprintf(stderr, " remsync [-xv] tree [diff-file]\n"); exit(1);}int main(int argc, char **argv){ int i; for (i= 1; i < argc && argv[i][0] == '-'; i++) { char *p= argv[i] + 1; if (p[0] == '-' && p[1] == 0) { i++; break; } while (*p != 0) { switch (*p++) { case 's': sflag= 1; break; case 'd': dflag= 1; break; case 'u': uflag= 1; break; case 'x': xflag= 1; break; case 'D': Dflag= 1; break; case 'v': vflag= 1; break; default: usage(); } } } if (sflag && dflag) usage(); if (sflag && uflag) usage(); if (!sflag && !dflag && uflag) usage(); if (!dflag && Dflag) usage(); if (i == argc) usage(); tree= argv[i++]; if (sflag) { /* Make a state file. */ state_file= i < argc ? argv[i++] : "-"; if (i != argc) usage(); statefp= stdout; if (strcmp(state_file, "-") != 0) { if ((statefp= fopen(state_file, "w")) == nil) fatal(state_file); } mkstatefile(); } else if (dflag) { /* Make a file of differences. */ state_file= i < argc ? argv[i++] : "-"; diff_file= i < argc ? argv[i++] : "-"; if (i != argc) usage(); statefp= stdin; if (strcmp(state_file, "-") != 0) { if ((statefp= fopen(state_file, "r")) == nil) fatal(state_file); } difffp= stdout; if (strcmp(diff_file, "-") != 0) { if ((difffp= fopen(diff_file, "w")) == nil) fatal(diff_file); } mkdifferences(); } else { /* Apply a file of differences. */ diff_file= i < argc ? argv[i++] : "-"; if (i != argc) usage(); difffp= stdin; if (strcmp(diff_file, "-") != 0) { if ((difffp= fopen(diff_file, "r")) == nil) fatal(diff_file); } apply_differences(); } exit(excode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -