erikb@cs.vu.nl (Erik Baalbergen) (05/11/87)
Next follows a simple program to copy a directory recursively. Use "cpdir [-v] src dst" to make a copy dst of directory src. Cpdir should behave like the UNIX shell command (cd src; tar cf - .) | (mkdir dst; cd dst; tar xf -) but the linking structure of the tree, and the owner and time information of files are not yet preserved. (See the work-yet-to-be-done list below.) The -v "verbose" flag enables you to see what's going on when running cpdir. Cheers, Erik Baalbergen <erikb@cs.vu.nl> ----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<---- /* Minix directory copy program -- Author: Erik Baalbergen */ /* Work yet to be done: - preserve link structure, times, etc... - 'stat' optimization (stat() is invoked twice for normal files) - link checks, i.e. am I not overwriting a file/directory by itself? * has been solved by letting 'cpdir' create the target directory - handle character and block special files * they're simply not copied Please report bugs and suggestions to erikb@cs.vu.nl */ #include <stdio.h> #ifdef UNIX #include <sys/types.h> #include <sys/stat.h> #define MKDIR "/bin/mkdir" #else !UNIX #include <stat.h> #define MKDIR "/usr/bin/mkdir" #endif #define BUFSIZE 1024 #define PLEN 256 #define DIRSIZ 16 char *prog; int vflag = 0; /* verbose */ char *strcpy(); main(argc, argv) char *argv[]; { int rc = 0; char *p, *s; prog = *argv++; if ((p = *argv) && *p == '-') { argv++; argc--; while (*++p) { switch (*p) { case 'v': vflag = 1; break; default: fatal("illegal flag %s", p); } } } if (argc != 3) fatal("use: [-v] source destination"); if (ftype(s = *argv++) != S_IFDIR) fatal("%s is not a directory", s); cpdir(s, *argv); exit(0); } cpdir(s, d) char *s, *d; { char spath[PLEN], dpath[PLEN]; char ent[DIRSIZ + 1]; register char *send = spath, *dend = dpath; int fd, n; while (*send++ = *s++) {} send--; while (*dend++ = *d++) {} if ((fd = open(spath, 0)) < 0) { nonfatal("can't read directory %s", spath); return; } *send++ = '/'; ent[DIRSIZ] = '\0'; mkdir(dpath); dend[-1] = '/'; while ((n = read(fd, ent, DIRSIZ)) == DIRSIZ) { if (!((ent[0] == '\0' && ent[1] == '\0') || (ent[2] == '.') && (ent[3] == '\0' || (ent[3] == '.' && ent[4] == '\0')) )) { strcpy(send, ent + 2); strcpy(dend, ent + 2); switch (ftype(spath)) { case S_IFDIR: cpdir(spath, dpath); break; case S_IFREG: cp(spath, dpath); break; default: nonfatal("can't copy special file %s", spath); } } } close(fd); if (n) fatal("error in reading directory %s", spath); } mkdir(s) char *s; { int pid, status; if (vflag) printf("mkdir %s\n", s); if ((pid = fork()) == 0) { execl(MKDIR, "mkdir", s, (char *)0); fatal("can't execute %s", MKDIR); } if (pid == -1) fatal("can't fork", prog); wait(&status); if (status) fatal("can't create %s", s); } cp(s, d) char *s, *d; { struct stat st; char buf[BUFSIZE]; int sfd, dfd, n; if (vflag) printf("cp %s %s\n", s, d); if ((sfd = open(s, 0)) < 0) nonfatal("can't read %s", s); else { if (fstat(sfd, &st) < 0) fatal("can't get file status of %s", s); if ((dfd = creat(d, st.st_mode & 0777)) < 0) fatal("can't create %s", d); while ((n = read(sfd, buf, BUFSIZE)) > 0) write(dfd, buf, n); close(sfd); close(dfd); if (n) fatal("error in reading file %s", s); } } ftype(s) char *s; { struct stat st; if (stat(s, &st) < 0) fatal("can't get file status of %s", s); return st.st_mode & S_IFMT; } nonfatal(s, a) char *s, *a; { fprintf(stderr, "%s: ", prog); fprintf(stderr, s, a); fprintf(stderr, "\n"); } fatal(s, a) char *s, *a; { nonfatal(s, a); exit(1); }