diff options
Diffstat (limited to 'nx-X11/config/util/mkshadow')
-rw-r--r-- | nx-X11/config/util/mkshadow/Imakefile | 5 | ||||
-rw-r--r-- | nx-X11/config/util/mkshadow/README | 38 | ||||
-rw-r--r-- | nx-X11/config/util/mkshadow/mkshadow.c | 378 | ||||
-rw-r--r-- | nx-X11/config/util/mkshadow/savedir.c | 119 | ||||
-rw-r--r-- | nx-X11/config/util/mkshadow/wildmat.c | 167 |
5 files changed, 707 insertions, 0 deletions
diff --git a/nx-X11/config/util/mkshadow/Imakefile b/nx-X11/config/util/mkshadow/Imakefile new file mode 100644 index 000000000..e8a879d97 --- /dev/null +++ b/nx-X11/config/util/mkshadow/Imakefile @@ -0,0 +1,5 @@ +XCOMM $Xorg: Imakefile,v 1.3 2000/08/17 19:41:53 cpqbld Exp $ + SRCS = mkshadow.c savedir.c wildmat.c + OBJS = mkshadow.o savedir.o wildmat.o + +ComplexProgramTarget(mkshadow) diff --git a/nx-X11/config/util/mkshadow/README b/nx-X11/config/util/mkshadow/README new file mode 100644 index 000000000..eea4b8b89 --- /dev/null +++ b/nx-X11/config/util/mkshadow/README @@ -0,0 +1,38 @@ +The mkshadow programs makes a "shadow tree" of a directory tree. +It logically copies all of the "MASTER" directory into ".". +However, ordinary files, and RCS/SCCS directories are "copied" +by creating a sybolic link to the corresponding file in MASTER. + +The wildmat.c file is by Rich Salz, and from comp.sources.misc, volume 17. +The savedir.c file is lightly modified from the version written +by David MacKenzie for GNU fileutils; the Free Software Foundation +has graciously agreed to waive their usual copyright so this +program can be distributed by the X Consortium. + +If you have problems compiling savedir.c, try setting the DIRENT make +variable as suggested in the Makefile. + + * Usage: mkshadow [-X exclude_file] [-x exclude_pattern] ... MASTER + * Makes the current directory be a "shadow copy" of MASTER. + * Sort of like a recursive copy of MASTER to . + * However, symbolic links are used instead of actually + * copying (non-directory) files. + * Also, directories named RCS or SCCS are shared (with a symbolic link). + * Warning messages are printed for files (and directories) in . + * that don't match a corresponding file in MASTER (though + * symbolic links are silently removed). + * Also, a warning message is printed for non-directory files + * under . that are not symbolic links. + * + * Files and directories can be excluded from the sharing + * with the -X and -x flags. The flag `-x pattern' (or `-xpattern') + * means that mkshadow should ignore any file whose name matches + * the pattern. The pattern is a "globbing" pattern, i.e. the + * characters *?[^-] are interpreted as by the shell. + * If the pattern contains a '/' is is matched against the complete + * current path (relative to '.'); otherwise, it is matched + * against the last component of the path. + * A `-X filename' flag means to read a set of exclusion patterns + * from the named file, one pattern to a line. + +Author: Per Bothner. bothner@cygnus.com. November 1990, 1993. diff --git a/nx-X11/config/util/mkshadow/mkshadow.c b/nx-X11/config/util/mkshadow/mkshadow.c new file mode 100644 index 000000000..d9c5eb841 --- /dev/null +++ b/nx-X11/config/util/mkshadow/mkshadow.c @@ -0,0 +1,378 @@ +/* $Xorg: mkshadow.c,v 1.3 2000/08/17 19:41:53 cpqbld Exp $ */ +/* mkshadow.c - make a "shadow copy" of a directory tree with symlinks. + Copyright 1990, 1993 Free Software Foundation, Inc. + + Permission to use, copy, modify, and distribute this program for + any purpose and without fee is hereby granted, provided that this + copyright and permission notice appear on all copies, and that + notice be given that copying and distribution is by permission of + the Free Software Foundation. The Free Software Foundation makes + no representations about the suitability of this software for any + purpose. It is provided "as is" without expressed or implied + warranty. + + (The FSF has modified its usual distribution terms, for this file, + as a courtesy to the X project.) */ + +/* + * Usage: mkshadow [-X exclude_file] [-x exclude_pattern] ... MASTER [SHADOW] + * Makes SHADOW be a "shadow copy" of MASTER. SHADOW defaults to the current + * directory. Sort of like a recursive copy of MASTER to SHADOW. + * However, symbolic links are used instead of actually + * copying (non-directory) files. + * Also, directories named RCS or SCCS are shared (with a symbolic link). + * Warning messages are printed for files (and directories) in . + * that don't match a corresponding file in MASTER (though + * symbolic links are silently removed). + * Also, a warning message is printed for non-directory files + * under SHADOW that are not symbolic links. + * + * Files and directories can be excluded from the sharing + * with the -X and -x flags. The flag `-x pattern' (or `-xpattern') + * means that mkshadow should ignore any file whose name matches + * the pattern. The pattern is a "globbing" pattern, i.e. the + * characters *?[^-] are interpreted as by the shell. + * If the pattern contains a '/' is is matched against the complete + * current path (relative to '.'); otherwise, it is matched + * against the last component of the path. + * A `-X filename' flag means to read a set of exclusion patterns + * from the named file, one pattern to a line. + * + * Originally written by Per Bothner at University of Wisconsin-Madison, + * inspired by the lndir script distributed with X11. + * Modified by Per Bothner <bothner@cygnus.com> November 1993 + * to more-or-less follow Posix. + */ + +#include <sys/types.h> +#include <stdio.h> +#ifdef BSD +#include <strings.h> +#define strchr index +#else +#include <string.h> +#endif +#include <sys/stat.h> +#if defined(S_IFDIR) && !defined(S_ISDIR) +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#if defined(S_IFLNK) && !defined(S_ISLNK) +#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif +#ifndef S_ISLNK +#define lstat stat +#endif +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +extern char * savedir(); + +fatal(msg) + char *msg; +{ + if (errno) perror(msg ? msg : ""); + else if (msg) fprintf(stderr, "mkshadow: %s\n", msg); + exit(-1); +} + +/* When handling symbolic links to relative directories, + * we need to prepend "../" to the "source". + * We preallocate MAX_DEPTH repetations of "../" using a simple trick. + */ +#define MAX_DEPTH 20 +#define PREPEND_BUFFER_SIZE (MAX_DEPTH*3) +char master_buffer[MAXPATHLEN+PREPEND_BUFFER_SIZE] = + "../../../../../../../../../../../../../../../../../../../../"; +/* The logical start of the master_buffer is defined by + * master_start, which skips the fixed prepend area. + */ +#define master_start (master_buffer+PREPEND_BUFFER_SIZE) +char shadow_buffer[MAXPATHLEN]; + +void bad_args(msg) +{ + if (msg) fprintf(stderr, "%s\n", msg); + fprintf (stderr, "usage: mkshadow [-X exclude_file] [-x exclude_pattern]"); + fprintf (stderr, " master [shadow]\n"); + exit(-1); +} + +int exclude_count = 0; +char **exclude_patterns = NULL; +int exclude_limit = 0; + +void add_exclude(pattern) + char *pattern; +{ + if (exclude_limit == 0) { + exclude_limit = 100; + exclude_patterns = (char**)malloc(exclude_limit * sizeof(char*)); + } else if (exclude_count + 1 >= exclude_limit) { + exclude_limit += 100; + exclude_patterns = (char**)realloc(exclude_patterns, + exclude_limit * sizeof(char*)); + } + exclude_patterns[exclude_count] = pattern; + exclude_count++; +} + +void add_exclude_file(name) + char *name; +{ + char buf[MAXPATHLEN]; + FILE *file = fopen(name, "r"); + if (file == NULL) fatal("failed to find -X (exclude) file"); + for (;;) { + int len; + char *str = fgets(buf, MAXPATHLEN, file); + if (str == NULL) break; + len = strlen(str); + if (len && str[len-1] == '\n') str[--len] = 0; + if (!len) continue; + str = (char*)malloc(len+1); + strcpy(str, buf); + add_exclude(str); + } + fclose(file); +} + +main(argc, argv) + char **argv; +{ + char *master_name = NULL; + char *shadow_name = NULL; + int i; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + switch(argv[i][1]) { + case 'X': + if (argv[i][2]) add_exclude_file(&argv[i][2]); + else if (++i >= argc) bad_args(NULL); + else add_exclude_file(argv[i]); + break; + case 'x': + if (argv[i][2]) add_exclude(&argv[i][2]); + else if (++i >= argc) bad_args(NULL); + else add_exclude(argv[i]); + break; + default: + bad_args(NULL); + } + } else if (master_name == NULL) + master_name = argv[i]; + else if (shadow_name == NULL) + shadow_name = argv[i]; + else bad_args (NULL); + } + + if (master_name == NULL) bad_args(NULL); + if (shadow_name == NULL) + shadow_name = "."; + else if ((shadow_name[0] != '.' || shadow_name[1]) + && master_name[0] != '/') { + fprintf(stderr, "Shadowing a relative directory pathname to a \n"); + fprintf(stderr, "shadow other than '.' is not supported!\n"); + exit(-1); + } + strcpy(shadow_buffer, shadow_name); + strcpy(master_start, master_name); + DoCopy(master_start, shadow_buffer, 0); + return 0; +} + +int compare_strings(ptr1, ptr2) + char **ptr1, **ptr2; +{ + return strcmp(*ptr1, *ptr2); +} + +void MakeLink(master, current, depth) + char *master; + char *current; + int depth; +{ + if (master[0] != '/') { + /* Source directory was specified with a relative pathname. */ + if (master != master_start) { + fatal("Internal bug: bad string buffer use"); + } + /* Pre-pend "../" depth times. This compensates for + * the directories we've entered. */ + master -= 3 * depth; + } + if (symlink(master, current)) { + fprintf(stderr, "Failed to create symbolic link %s->%s\n", + current, master); + exit (-1); + } +} + + +/* Get a sorted NULL_terminator array of (char*) using 'names' + * (created by save_dir) as data. + */ +char ** get_name_pointers(names) + char *names; +{ + int n_names = 0; + int names_buf_size = 64; + char *namep; + char ** pointers = (char**)malloc(names_buf_size * sizeof(char*)); + if (!names || !pointers) fatal("virtual memory exhausted"); + + for (namep = names; *namep; namep += strlen(namep) + 1) { + if (n_names + 1 >= names_buf_size) { + names_buf_size *= 2; + pointers = (char**)realloc(pointers, + names_buf_size * sizeof(char*)); + if (!pointers) fatal("virtual memory exhausted"); + } + pointers[n_names++] = namep; + } + pointers[n_names] = 0; + qsort(pointers, n_names, sizeof(char*), compare_strings); + return pointers; +} + +/* Recursively shadow the directory whose name is in MASTER + * (which is == MASTER_START) into the destination directory named CURRENT. + */ + +DoCopy(master, current, depth) + char *master; /* The source directory. */ + char *current; /* The destination directory. */ + int depth; +{ + struct stat stat_master, stat_current; + char **master_pointer, **current_pointer; + char **master_names, **current_names; + char *master_end, *current_end; + char *master_name_buf, *current_name_buf; + master_end = master + strlen(master); + current_end = current + strlen(current); + + /* Get rid of terminal '/' */ + if (master_end[-1] == '/' && master != master_end - 1) + *--master_end = 0; + if (current_end[-1] == '/' && current != current_end - 1) + *--current_end = 0; + + if (depth >= MAX_DEPTH) { + fprintf(stderr, + "Nesting too deep (depth %d at %s). Probable circularity.\n", + depth, master); + exit(-1); + } + + master_name_buf = savedir(master, 500); + if (master_name_buf == NULL) { + fprintf(stderr, "Not enough memory or no such directory: %s\n", + master); + exit(-1); + } + current_name_buf = savedir(current, 500); + if (current_name_buf == NULL) { + fprintf(stderr, "Not enough memory or no such directory: %s\n", + current); + exit(-1); + } + + master_names = get_name_pointers(master_name_buf); + current_names = get_name_pointers(current_name_buf); + + master_pointer = master_names; + current_pointer = current_names; + for (;;) { + int cmp, ipat; + int in_master, in_current; + char *cur_name; + if (*master_pointer == NULL && *current_pointer == NULL) + break; + if (*master_pointer == NULL) cmp = 1; + else if (*current_pointer == NULL) cmp = -1; + else cmp = strcmp(*master_pointer, *current_pointer); + if (cmp < 0) { /* file only exists in master directory */ + in_master = 1; in_current = 0; + } else if (cmp == 0) { /* file exists in both directories */ + in_master = 1; in_current = 1; + } else { /* file only exists in current directory */ + in_current = 1; in_master = 0; + } + cur_name = in_master ? *master_pointer : *current_pointer; + sprintf(master_end, "/%s", cur_name); + sprintf(current_end, "/%s", cur_name); + for (ipat = 0; ipat < exclude_count; ipat++) { + char *pat = exclude_patterns[ipat]; + char *cur; + if (strchr(pat, '/')) cur = current + 2; /* Skip initial "./" */ + else cur = cur_name; + if (wildmat(cur, pat)) goto skip; + } + if (in_master) + if (lstat(master, &stat_master) != 0) fatal("stat failed"); + if (in_current) + if (lstat(current, &stat_current) != 0) fatal("stat failed"); + if (in_current && !in_master) { + if (S_ISLNK(stat_current.st_mode)) + if (unlink(current)) { + fprintf(stderr, "Failed to remove symbolic link %s.\n", + current); + } + else + fprintf(stderr, "Removed symbolic link %s.\n", + current); + else { + fprintf(stderr, + "The file %s does not exist in the master tree.\n", + current); + } + } + else if (S_ISDIR(stat_master.st_mode) + && strcmp(cur_name, "RCS") != 0 + && strcmp(cur_name, "SCCS") != 0) { + if (!in_current) { + if (mkdir(current, 0775)) fatal("mkdir failed"); + } + else if (stat(current, &stat_current)) fatal("stat failed"); + if (!in_current || stat_current.st_dev != stat_master.st_dev + || stat_current.st_ino != stat_master.st_ino) + DoCopy(master, current, depth+1); + else + fprintf(stderr, "Link %s is the same as directory %s.\n", + current, master); + } + else { + if (!in_current) + MakeLink(master, current, depth); + else if (!S_ISLNK(stat_current.st_mode)) { + fprintf(stderr, "Existing file %s is not a symbolic link.\n", + current); + } else { + if (stat(current, &stat_current) || stat(master, &stat_master)) + fatal("stat failed"); + if (stat_current.st_dev != stat_master.st_dev + || stat_current.st_ino != stat_master.st_ino) { + fprintf(stderr, "Fixing incorrect symbolic link %s.\n", + current); + if (unlink(current)) { + fprintf(stderr, "Failed to remove symbolic link %s.\n", + current); + } + else + MakeLink(master, current, depth); + } + } + } + skip: + if (in_master) master_pointer++; + if (in_current) current_pointer++; + } + + free(master_names); free(current_names); + free(master_name_buf); free(current_name_buf); +} diff --git a/nx-X11/config/util/mkshadow/savedir.c b/nx-X11/config/util/mkshadow/savedir.c new file mode 100644 index 000000000..6629f5a8d --- /dev/null +++ b/nx-X11/config/util/mkshadow/savedir.c @@ -0,0 +1,119 @@ +/* $Xorg: savedir.c,v 1.3 2000/08/17 19:41:53 cpqbld Exp $ */ +/* savedir.c -- save the list of files in a directory in a string + Copyright 1990, 1993 Free Software Foundation, Inc. + + Permission to use, copy, modify, and distribute this program for + any purpose and without fee is hereby granted, provided that this + copyright and permission notice appear on all copies, and that + notice be given that copying and distribution is by permission of + the Free Software Foundation. The Free Software Foundation makes + no representations about the suitability of this software for any + purpose. It is provided "as is" without expressed or implied + warranty. + + (The FSF has modified its usual distribution terms, for this file, + as a courtesy to the X project.) */ + +/* $XFree86$ */ + +/* Written by David MacKenzie <djm@ai.mit.edu>. + Modified to use <dirent.h> by default. Per Bothner <bothner@cygnus.com>. */ + +#include <sys/types.h> +#if !defined(DIRECT) && !defined(BSD) +#include <dirent.h> +#define NLENGTH(direct) (strlen((direct)->d_name)) +#else +#undef dirent +#define dirent direct +#define NLENGTH(direct) ((direct)->d_namlen) +#ifdef BSD +#include <sys/dir.h> +#else +#ifdef SYSNDIR +#include <sys/ndir.h> +#else +#include <ndir.h> +#endif +#endif +#endif + +#if defined(VOID_CLOSEDIR) || defined(BSD) +/* Fake a return value. */ +#define CLOSEDIR(d) (closedir (d), 0) +#else +#define CLOSEDIR(d) closedir (d) +#endif + +#include <stdlib.h> +#include <string.h> +#include <stddef.h> + +char *stpcpy (); + +/* Return a freshly allocated string containing the filenames + in directory DIR, separated by '\0' characters; + the end is marked by two '\0' characters in a row. + NAME_SIZE is the number of bytes to initially allocate + for the string; it will be enlarged as needed. + Return NULL if DIR cannot be opened or if out of memory. */ + +char * +savedir (dir, name_size) + char *dir; + unsigned name_size; +{ + DIR *dirp; + struct dirent *dp; + char *name_space; + char *namep; + + dirp = opendir (dir); + if (dirp == NULL) + return NULL; + + name_space = (char *) malloc (name_size); + if (name_space == NULL) + { + closedir (dirp); + return NULL; + } + namep = name_space; + + while ((dp = readdir (dirp)) != NULL) + { + /* Skip "." and ".." (some NFS filesystems' directories lack them). */ + if (dp->d_name[0] != '.' + || (dp->d_name[1] != '\0' + && (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) + { + unsigned size_needed = (namep - name_space) + NLENGTH (dp) + 2; + + if (size_needed > name_size) + { + char *new_name_space; + + while (size_needed > name_size) + name_size += 1024; + + new_name_space = realloc (name_space, name_size); + if (new_name_space == NULL) + { + closedir (dirp); + return NULL; + } + namep += new_name_space - name_space; + name_space = new_name_space; + } + strcpy (namep, dp->d_name); + namep += strlen (namep) + 1; + } + } + *namep = '\0'; + if (CLOSEDIR (dirp)) + { + free (name_space); + return NULL; + } + return name_space; +} diff --git a/nx-X11/config/util/mkshadow/wildmat.c b/nx-X11/config/util/mkshadow/wildmat.c new file mode 100644 index 000000000..8e0c179eb --- /dev/null +++ b/nx-X11/config/util/mkshadow/wildmat.c @@ -0,0 +1,167 @@ +/* $Xorg: wildmat.c,v 1.3 2000/08/17 19:41:53 cpqbld Exp $ */ +/* +** +** Do shell-style pattern matching for ?, \, [], and * characters. +** Might not be robust in face of malformed patterns; e.g., "foo[a-" +** could cause a segmentation violation. It is 8bit clean. +** +** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. +** Rich $alz is now <rsalz@bbn.com>. +** April, 1991: Replaced mutually-recursive calls with in-line code +** for the star character. +** +** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code. +** This can greatly speed up failing wildcard patterns. For example: +** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-* +** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 +** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 +** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without +** the ABORT, then it takes 22310 calls to fail. Ugh. The following +** explanation is from Lars: +** The precondition that must be fulfilled is that DoMatch will consume +** at least one character in text. This is true if *p is neither '*' nor +** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic +** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With +** FALSE, each star-loop has to run to the end of the text; with ABORT +** only the last one does. +** +** Once the control of one instance of DoMatch enters the star-loop, that +** instance will return either TRUE or ABORT, and any calling instance +** will therefore return immediately after (without calling recursively +** again). In effect, only one star-loop is ever active. It would be +** possible to modify the code to maintain this context explicitly, +** eliminating all recursive calls at the cost of some complication and +** loss of clarity (and the ABORT stuff seems to be unclear enough by +** itself). I think it would be unwise to try to get this into a +** released version unless you have a good test data base to try it out +** on. +*/ + +#define TRUE 1 +#define FALSE 0 +#define ABORT -1 + + + /* What character marks an inverted character class? */ +#define NEGATE_CLASS '^' + /* Is "*" a common pattern? */ +#define OPTIMIZE_JUST_STAR + /* Do tar(1) matching rules, which ignore a trailing slash? */ +#undef MATCH_TAR_PATTERN + + +/* +** Match text and p, return TRUE, FALSE, or ABORT. +*/ +static int +DoMatch(text, p) + register char *text; + register char *p; +{ + register int last; + register int matched; + register int reverse; + + for ( ; *p; text++, p++) { + if (*text == '\0' && *p != '*') + return ABORT; + switch (*p) { + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if (*text != *p) + return FALSE; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while (*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if (*p == '\0') + /* Trailing star matches everything. */ + return TRUE; + while (*text) + if ((matched = DoMatch(text++, p)) != FALSE) + return matched; + return ABORT; + case '[': + reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE; + if (reverse) + /* Inverted character class. */ + p++; + for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p) + /* This next line requires a good C compiler. */ + if (*p == '-' ? *text <= *++p && *text >= last : *text == *p) + matched = TRUE; + if (matched == reverse) + return FALSE; + continue; + } + } + +#ifdef MATCH_TAR_PATTERN + if (*text == '/') + return TRUE; +#endif /* MATCH_TAR_ATTERN */ + return *text == '\0'; +} + + +/* +** User-level routine. Returns TRUE or FALSE. +*/ +int +wildmat(text, p) + char *text; + char *p; +{ +#ifdef OPTIMIZE_JUST_STAR + if (p[0] == '*' && p[1] == '\0') + return TRUE; +#endif /* OPTIMIZE_JUST_STAR */ + return DoMatch(text, p) == TRUE; +} + + + +#ifdef TEST +#include <stdio.h> + +/* Yes, we use gets not fgets. Sue me. */ +extern char *gets(); + + +main() +{ + char p[80]; + char text[80]; + + printf("Wildmat tester. Enter pattern, then strings to test.\n"); + printf("A blank line gets prompts for a new pattern; a blank pattern\n"); + printf("exits the program.\n"); + + for ( ; ; ) { + printf("\nEnter pattern: "); + (void)fflush(stdout); + if (gets(p) == NULL || p[0] == '\0') + break; + for ( ; ; ) { + printf("Enter text: "); + (void)fflush(stdout); + if (gets(text) == NULL) + exit(0); + if (text[0] == '\0') + /* Blank line; go back and get a new pattern. */ + break; + printf(" %s\n", wildmat(text, p) ? "YES" : "NO"); + } + } + + exit(0); + /* NOTREACHED */ +} +#endif /* TEST */ |