#include <X11/Xos.h>
#include <X11/Xfuncproto.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#if !defined(MINIX) && !defined(Lynx)
#include <sys/param.h>
#endif
#include <errno.h>
#ifndef X_NOT_POSIX
#include <dirent.h>
#else
#ifdef SYSV
#include <dirent.h>
#else
#ifdef USG
#include <dirent.h>
#else
#include <sys/dir.h>
#ifndef dirent
#define dirent direct
#endif
#endif
#endif
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 2048
#endif
#include <stdarg.h>
int silent = 0;
int ignore_links = 0;
int with_revinfo = 0;
char *rcurdir;
char *curdir;
static void
quit (int code, char * fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf (stderr, fmt, args);
va_end(args);
putc ('\n', stderr);
exit (code);
}
static void
quiterr (int code, char *s)
{
perror (s);
exit (code);
}
static void
msg (char * fmt, ...)
{
va_list args;
if (curdir) {
fprintf (stderr, "%s:\n", curdir);
curdir = 0;
}
va_start(args, fmt);
vfprintf (stderr, fmt, args);
va_end(args);
putc ('\n', stderr);
}
static void
mperror (char *s)
{
if (curdir) {
fprintf (stderr, "%s:\n", curdir);
curdir = 0;
}
perror (s);
}
static int
equivalent(char *lname, char *rname, char **p)
{
char *s;
if (!strcmp(lname, rname))
return 1;
for (s = lname; *s && (s = strchr(s, '/')); s++) {
while (s[1] == '/') {
strcpy(s+1, s+2);
if (*p) (*p)--;
}
}
return !strcmp(lname, rname);
}
static int
dodir (char *fn,
struct stat *fs,
struct stat *ts,
int rel)
{
DIR *df;
struct dirent *dp;
char buf[MAXPATHLEN + 1], *p;
char symbuf[MAXPATHLEN + 1];
char basesym[MAXPATHLEN + 1];
struct stat sb, sc;
int n_dirs;
int symlen;
int basesymlen = -1;
char *ocurdir;
if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
msg ("%s: From and to directories are identical!", fn);
return 1;
}
if (rel)
strcpy (buf, "../");
else
buf[0] = '\0';
strcat (buf, fn);
if (!(df = opendir (buf))) {
msg ("%s: Cannot opendir", buf);
return 1;
}
p = buf + strlen (buf);
if (*(p - 1) != '/')
*p++ = '/';
n_dirs = fs->st_nlink;
while ((dp = readdir (df))) {
if (dp->d_name[strlen(dp->d_name) - 1] == '~')
continue;
#ifdef __DARWIN__
if (!strcmp(dp->d_name, ".DS_Store") ||
!strcmp(dp->d_name, "._.DS_Store"))
continue;
#endif
strcpy (p, dp->d_name);
if (n_dirs > 0) {
if (stat (buf, &sb) < 0) {
mperror (buf);
continue;
}
#ifdef S_ISDIR
if(S_ISDIR(sb.st_mode))
#else
if (sb.st_mode & S_IFDIR)
#endif
{
n_dirs--;
if (dp->d_name[0] == '.' &&
(dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
dp->d_name[2] == '\0')))
continue;
if (!with_revinfo) {
if (!strcmp (dp->d_name, "BitKeeper"))
continue;
if (!strcmp (dp->d_name, "RCS"))
continue;
if (!strcmp (dp->d_name, "SCCS"))
continue;
if (!strcmp (dp->d_name, "CVS"))
continue;
if (!strcmp (dp->d_name, "CVS.adm"))
continue;
if (!strcmp (dp->d_name, ".svn"))
continue;
}
ocurdir = rcurdir;
rcurdir = buf;
curdir = silent ? buf : (char *)0;
if (!silent)
printf ("%s:\n", buf);
if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
if (mkdir (dp->d_name, 0777) < 0 ||
stat (dp->d_name, &sc) < 0) {
mperror (dp->d_name);
curdir = rcurdir = ocurdir;
continue;
}
}
if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
msg ("%s: is a link instead of a directory", dp->d_name);
curdir = rcurdir = ocurdir;
continue;
}
if (chdir (dp->d_name) < 0) {
mperror (dp->d_name);
curdir = rcurdir = ocurdir;
continue;
}
dodir (buf, &sb, &sc, (buf[0] != '/'));
if (chdir ("..") < 0)
quiterr (1, "..");
curdir = rcurdir = ocurdir;
continue;
}
}
symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
if (symlen >= 0)
symbuf[symlen] = '\0';
if (!ignore_links) {
basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
if (basesymlen >= 0)
basesym[basesymlen] = '\0';
}
if (symlen >= 0) {
if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf,
basesymlen>=0 ? (char **) 0 : &p))
msg ("%s: %s", dp->d_name, symbuf);
} else {
char *sympath;
if (basesymlen>=0) {
if ((buf[0] == '.') && (buf[1] == '.') && (buf[2] == '/') &&
(basesym[0] == '.') && (basesym[1] == '.') &&
(basesym[2] == '/')) {
int i;
char *start, *end;
strcpy (symbuf, buf);
start = symbuf;
do {
start += 3;
} while ((start[0] == '.') && (start[1] == '.') &&
(start[2] == '/'));
i = 0;
end = strrchr (symbuf, '/');
if (start < end) {
do {
i += 3;
end--;
while ((*end != '/') && (end != start))
end--;
if (end == start)
break;
} while ((basesym[i] == '.') &&
(basesym[i + 1] == '.') &&
(basesym[i + 2] == '/'));
}
if (*end == '/')
end++;
strcpy (end, &basesym[i]);
sympath = symbuf;
}
else
sympath = basesym;
}
else
sympath = buf;
if (symlink (sympath, dp->d_name) < 0)
mperror (dp->d_name);
}
}
closedir (df);
return 0;
}
int
main (int ac, char *av[])
{
char *prog_name = av[0];
char *fn, *tn;
struct stat fs, ts;
while (++av, --ac) {
if (strcmp(*av, "-silent") == 0)
silent = 1;
else if (strcmp(*av, "-ignorelinks") == 0)
ignore_links = 1;
else if (strcmp(*av, "-withrevinfo") == 0)
with_revinfo = 1;
else if (strcmp(*av, "--") == 0) {
++av, --ac;
break;
}
else
break;
}
if (ac < 1 || ac > 2)
quit (1, "usage: %s [-silent] [-ignorelinks] fromdir [todir]",
prog_name);
fn = av[0];
if (ac == 2)
tn = av[1];
else
tn = ".";
if (stat (tn, &ts) < 0)
quiterr (1, tn);
#ifdef S_ISDIR
if (!(S_ISDIR(ts.st_mode)))
#else
if (!(ts.st_mode & S_IFDIR))
#endif
quit (2, "%s: Not a directory", tn);
if (chdir (tn) < 0)
quiterr (1, tn);
if (stat (fn, &fs) < 0)
quiterr (1, fn);
#ifdef S_ISDIR
if (!(S_ISDIR(fs.st_mode)))
#else
if (!(fs.st_mode & S_IFDIR))
#endif
quit (2, "%s: Not a directory", fn);
exit (dodir (fn, &fs, &ts, 0));
}