[comp.windows.x] Faster version of lndir

mlandau@bbn.com (Matt Landau) (01/06/90)

The idea of using lndir to create a tree of links to the X11R4 sources
for compilation on different machines is a nice one, but when you try
to put it into practice, you find that lndir is painfully slow (being
a recursive shell script and all... :-)

Here's a program that does the same thing, using the same syntax, but
running about 3 times faster because it's written in C.  (It's still
too slow, but profiling shows that most of the time is spent in the
symlink system call, and I don't really know how to speed that up...)

Caveat user: this program is a quick little hack because I needed
something that would build a link tree in 45 minutes instead of 2.5
hours.  It works on my Suns and VAXen, and hasn't been tested on
anything else.  It probably won't work on an Amiga, which doesn't 
have ".." directories :-)

Share and enjoy...
--
 Matt Landau			Waiting for a flash of enlightenment
 mlandau@bbn.com			  in all this blood and thunder


------------------------ Cut here to get linktree.c ---------------------

/*
 * The program builds a tree of symbolic links, like the X11R4 lndir.sh
 * script, but much faster.  Share and Enjoy...
 *
 *				- Matt Landau  (mlandau@bbn.com)
 *				  BBN Systems and Technologies Corp.
 *				  1/6/90
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <sys/param.h>

static int is_directory(name, sp)
char *name;
struct stat *sp;
{   

    if (stat(name, sp) < 0)
    {   
	perror(name);
	return (0);
    }
    return (sp->st_mode & S_IFDIR);
}


static void link_dir(from_name, to_name)
char *from_name, *to_name;
{   
    struct stat s1, s2;
    DIR *dir;
    struct direct *dir_entry;
    char name[MAXPATHLEN];
    char src_path[MAXPATHLEN], dst_path[MAXPATHLEN];
    
    if (!is_directory(from_name, &s1) || !is_directory(to_name, &s2))
	return;

    if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino)
    {   
	fprintf(stderr, "%s and %s are identical\n", from_name, to_name);
	return;
    }
    
    if ((dir = opendir(from_name)) == NULL)
    {   
	perror(from_name);
	return;
    }
    
    printf("%s:\n", from_name);
    while ((dir_entry = readdir(dir)) != NULL)
    {   
	strcpy(name, dir_entry->d_name);
	if (!strcmp(name, ".") || !strcmp(name, ".."))
	    continue;
	sprintf(src_path, "%s/%s", from_name, name);
	if (!is_directory(src_path, &s1))
	{   
	    sprintf(dst_path, "%s/%s", to_name, name);
	    if (symlink(src_path, dst_path) < 0)
		perror(dst_path);
	}
	else
	{   
	    sprintf(dst_path, "%s/%s", to_name, name);
	    if (mkdir(dst_path, 0777) < 0)
	    {   
		perror(dst_path);
		continue;
	    }
	    if (chdir(dst_path) < 0)
	    {   
		perror(dst_path);
		continue;
	    }
	    sprintf(src_path, "../%s/%s", from_name, name);
	    link_dir(src_path, ".");
	    if (chdir("..") < 0)
	    {   
		perror("Panic!  Cannot return to parent directory");
		exit(2);
	    }
	}
    }
}

	
main(argc, argv)
int argc;
char *argv[];
{   
    if (argc != 2)
    {
	fprintf(stderr, "usage: %s from\n", argv[0]);
	exit(1);
    }
    link_dir(argv[1], ".");
}

mlandau@bbn.com (Matt Landau) (01/08/90)

Yes, Virginia, you DO need to add a "closedir(dir)" at the end of 
the link_dir routine, outside the while loop, lest you run out of 
file descriptors when building a copy of then entire X11 tree...