/* Copyright (C) 1990, Digital Equipment Corporation. */ /* All rights reserved. */ /* See the file COPYRIGHT for a full description. */ /* Last modified on Wed Jul 18 01:11:33 1990 by muller */ #include #include #include #include #include #include #include #if defined (AIX386) #define gd_name d_name #endif #define NEW(t) (t *) (malloc (sizeof (t))) #if defined (IBMRT) || defined (IBMR2) extern int errno; #endif #if defined (IBMRT) || defined (IBMR2) || defined (SPARC) #define gd_name d_name #endif char *src_dir; char *dst_dir; char *back_to_parent; int verbose = 0; int partial_clone = 0; char * to_clone[10000]; void error (va_alist) va_dcl { va_list args; char msg [1000]; char *fmt; va_start (args); fmt = va_arg (args, char *); #if defined (IBMRT) sprintf (msg, fmt. args); #else vsprintf (msg, fmt, args); #endif va_end (args); perror (msg); exit (1); } char *concat (t, u) char *t; char *u; { int n = strlen (t) + strlen (u) + 1; char *res = (char *) malloc (n); strcpy (res, t); strcat (res, u); return (res); } int min (a, b) int a, b; { if (a > b) { return b; } else { return a; } } int should_I_clone (path) char *path; { int i; if (partial_clone == 0) { return 1; } for (i = 0; i < partial_clone; i++) { if (strncmp (to_clone[i], path, min (strlen (to_clone[i]), strlen (path))) == 0) { return 1; }} return 0; } void mkdir_may_exist (path) char *path; { if ((mkdir (path, 0777) != 0) && (errno != EEXIST)) { error ("mkdir (%s)", path); } } void symlink_may_exist (to, from) char *to, *from; { int n; char name [MAXPATHLEN]; while (1) { if (symlink (to, from)) { if (errno == EEXIST) { if ((n = readlink (from, name, MAXPATHLEN)) < 0) { if (errno != EINVAL) { error ("readlink (%s)", from); }} else { name [n] = '\0'; if (strcmp (name, to) == 0) { return; }} if (unlink (from) != 0) { error ("unlink (%s)", from); }} else { error ("symlink (%s -> %s)", from, to); }} else { return; }} } typedef struct to_process { char *path; int depth; struct to_process *next; } *TO_PROCESS; TO_PROCESS new_TO_PROCESS (path, depth, next) char *path; int depth; TO_PROCESS next; { TO_PROCESS new = NEW (struct to_process); new->path = path; new->depth = depth; new->next = next; return (new); } char up_res [MAXPATHLEN]; char *up (n, name) int n; char *name; { int i; for (i = 0; i < n; i++) { up_res [i * 3 ] = '.'; up_res [i * 3 + 1] = '.'; up_res [i * 3 + 2] = '/'; } up_res [n * 3] = '\0'; strcat (up_res, name); return (up_res); } int lftw (path, fn) char* path; int (*fn) (); { TO_PROCESS current_dir, to_process; struct stat statbuf; DIR *dir; struct direct *file; char *file_name; to_process = new_TO_PROCESS (path, 0, NULL); while (to_process != NULL) { current_dir = to_process; to_process = to_process->next; if (! should_I_clone (current_dir->path)) { continue; } if (verbose) { fprintf (stderr, "%s\n", current_dir->path); } if ((dir = opendir (current_dir->path)) == NULL) { error ("opendir"); } while ((file = readdir (dir)) != NULL) { if ((strcmp (file->gd_name, ".") != 0) && (strcmp (file->gd_name, "..") != 0)) { file_name = concat (current_dir->path, concat ("/", file->gd_name)); if (lstat (file_name, &statbuf) != 0) { error ("fstat on %s", file_name); } if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { TO_PROCESS another = new_TO_PROCESS (file_name, current_dir->depth + 1, to_process); to_process = another; fn (current_dir->path, file->gd_name, current_dir->depth + 1, &statbuf); } else { fn (current_dir->path, file->gd_name, current_dir->depth + 1, &statbuf); }}} #if defined(IBMRT) closedir (dir);} /* Doesn't return anything on IBM/4.3 */ #else if (closedir (dir) != NULL) { error ("closedir"); }} #endif } int trace (path, name, depth, statbuf) char *path; char *name; int depth; struct stat *statbuf; { switch (statbuf->st_mode & S_IFMT) { case S_IFDIR: printf ("/ "); break; case S_IFLNK: printf ("@ "); break; case S_IFREG: printf (" "); break; default: printf ("? "); break; } printf ("%s/%s %d\n", path, name, depth); } int recursive_src_clone (path, name, depth, statbuf) char *path; char *name; int depth; struct stat *statbuf; { char *rel_path = concat (path + strlen (src_dir), concat ("/", name)); char *new_name = concat (dst_dir, concat ("/", rel_path)); switch (statbuf->st_mode & S_IFMT) { case S_IFDIR: { mkdir_may_exist (new_name, 0777); symlink_may_exist (up (depth, "."), concat (new_name, "/.ROOT")); symlink_may_exist (concat (up (depth, "RCS"), rel_path), concat (new_name, "/RCS")); symlink_may_exist (".", concat (new_name, "/.SRC")); break; } case S_IFLNK: break; case S_IFREG: { char command [MAXPATHLEN + 100]; char cwd [MAXPATHLEN]; if (getwd (cwd) == 0) { error ("getwd"); } sprintf (command, "cd %s/%s/%s; co -q %s", cwd, dst_dir, path + strlen (src_dir), name); system (command); break; } default: error ("unknown type %d", statbuf->st_mode & S_IFMT); break; } } void src_clone () { char cwd [MAXPATHLEN]; mkdir_may_exist (dst_dir); symlink_may_exist (".", concat (dst_dir, "/.ROOT")); if (src_dir[0] == '/') { symlink_may_exist (src_dir, concat (dst_dir, "/RCS")); } else { if (getwd (cwd) == 0) { error ("getwd"); } symlink_may_exist (concat (cwd, concat ("/", src_dir)), concat (dst_dir, "/RCS")); } symlink_may_exist (".", concat (dst_dir, "/.SRC")); lftw (src_dir, recursive_src_clone); } int recursive_work_clone (path, name, depth, statbuf) char *path; char *name; int depth; struct stat *statbuf; { char *rel_path = concat (path + strlen (src_dir), concat ("/", name)); char *new_name = concat (dst_dir, concat ("/", rel_path)); switch (statbuf->st_mode & S_IFMT) { case S_IFDIR: { mkdir_may_exist (new_name, 0777); symlink_may_exist (up (depth, "."), concat (new_name, "/.ROOT")); symlink_may_exist (concat (up (depth, ".SRC"), rel_path), concat (new_name, "/.SRC")); break; } case S_IFLNK: break; case S_IFREG: { symlink_may_exist (concat (".SRC/", name), new_name); break; } default: error ("unknown type %d", statbuf->st_mode & S_IFMT); break; } } void work_clone () { char cwd [MAXPATHLEN]; mkdir_may_exist (dst_dir); symlink_may_exist (".", concat (dst_dir, "/.ROOT")); if (src_dir[0] == '/') { symlink_may_exist (src_dir, concat (dst_dir, "/.SRC")); } else { if (getwd (cwd) == 0) { error ("getwd"); } symlink_may_exist (concat (cwd, concat ("/", src_dir)), concat (dst_dir, "/.SRC")); } lftw (src_dir, recursive_work_clone); } int recursive_copy_clone (path, name, depth, statbuf) char *path; char *name; int depth; struct stat *statbuf; { char *rel_path = concat (path + strlen (src_dir), concat ("/", name)); char *new_name = concat (dst_dir, concat ("/", rel_path)); switch (statbuf->st_mode & S_IFMT) { case S_IFDIR: { mkdir_may_exist (new_name, 0777); symlink_may_exist (up (depth, "."), concat (new_name, "/.ROOT")); break; } case S_IFLNK: break; case S_IFREG: { char command [MAXPATHLEN + 100]; sprintf (command, "cp %s/%s %s", path, name, new_name); system (command); break; } default: error ("unknown type %d", statbuf->st_mode & S_IFMT); break; } } void copy_clone () { char cwd [MAXPATHLEN]; mkdir_may_exist (dst_dir); symlink_may_exist (".", concat (dst_dir, "/.ROOT")); lftw (src_dir, recursive_copy_clone); } main (argc, argv) int argc; char **argv; { int do_src = 0; int do_work = 0; int do_copy = 0; int bad_usage = 0; int action_specified = 0; int i; argv++; argc--; while ((argc > 0) && (argv[0][0] == '-')) { switch (argv [0][1]) { case 's': if (action_specified) { bad_usage = 1; } else { action_specified = 1; do_src = 1; } break; case 'w': if (action_specified) { bad_usage = 1; } else { action_specified = 1; do_work = 1; } break; case 'c': if (action_specified) { bad_usage = 1; } else { action_specified = 1; do_copy = 1; } break; case 'v': verbose = 1; break; case 'o': to_clone [partial_clone++] = argv[0] + 2; break; default: bad_usage = 1; break; } argv++; argc--; } if (bad_usage || (action_specified == 0) || (argc < 2)) { fprintf (stderr, "usage: clone [-v] { -s | -w | -c} [-odir]* source dest\n"); exit (1); } src_dir = argv[0]; dst_dir = argv[1]; for (i = 0; i < partial_clone; i++) { to_clone [i] = concat (src_dir, concat ("/", to_clone[i])); } if (do_src) { src_clone (); } if (do_work) { work_clone (); } if (do_copy) { copy_clone (); } }