X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=utils%2Flndir%2Flndir.c;h=6cc240a97834501b7f2f2bd76691528b5f7b8c9d;hb=f74a6116eb089646eec41755eccbe0eb88a99ac0;hp=c65715e3791997e6f27aaab56753fa1e0daad097;hpb=0065d5ab628975892cea1ec7303f968c3338cbe1;p=ghc-hetmet.git diff --git a/utils/lndir/lndir.c b/utils/lndir/lndir.c index c65715e..6cc240a 100644 --- a/utils/lndir/lndir.c +++ b/utils/lndir/lndir.c @@ -38,9 +38,9 @@ in this Software without prior written authorization from the X Consortium. If your master sources are located in /usr/local/src/X and you would like your link tree to be in /usr/local/src/new-X, do the following: - % mkdir /usr/local/src/new-X - % cd /usr/local/src/new-X - % lndir ../X + % mkdir /usr/local/src/new-X + % cd /usr/local/src/new-X + % lndir ../X */ #include "lndir-Xos.h" @@ -81,14 +81,26 @@ in this Software without prior written authorization from the X Consortium. #ifdef X_NOT_STDC_ENV extern int errno; #endif -int silent = 0; /* -silent */ -int ignore_links = 0; /* -ignorelinks */ +int silent = 0; /* -silent */ +int copy = 0; /* -copy */ +int ignore_links = 0; /* -ignorelinks */ char *rcurdir; char *curdir; int force=0; +#ifdef WIN32 +#define mymkdir(X, Y) mkdir(X) +#else +#define mymkdir(X, Y) mkdir(X, Y) +#endif + +#ifndef WIN32 +#define SYMLINKS +#define BELIEVE_ST_NLINK +#endif + void quit ( #if NeedVarargsPrototypes @@ -131,8 +143,8 @@ msg ( va_list args; #endif if (curdir) { - fprintf (stderr, "%s:\n", curdir); - curdir = 0; + fprintf (stderr, "%s:\n", curdir); + curdir = 0; } #if NeedVarargsPrototypes va_start(args, fmt); @@ -149,12 +161,64 @@ mperror (s) char *s; { if (curdir) { - fprintf (stderr, "%s:\n", curdir); - curdir = 0; + fprintf (stderr, "%s:\n", curdir); + curdir = 0; } perror (s); } +#define BUFSIZE 1024 +int copyfile(const char *oldpath, const char *newpath) { + FILE *f_old; + FILE *f_new; + int e; + ssize_t s; + char buf[BUFSIZE]; + +#ifdef SYMLINKS + if (copy) { + return symlink(oldpath, newpath); + } else { +#endif + f_old = fopen(oldpath, "rb"); + if (f_old == NULL) { + return -1; + } + f_new = fopen(newpath, "wbx"); + if (f_new == NULL) { + e = errno; + fclose(f_old); + errno = e; + return -1; + } + while ((s = fread(buf, 1, BUFSIZE, f_old)) > 0) { + if (fwrite(buf, 1, s, f_new) < s) { + e = errno; + fclose(f_old); + fclose(f_new); + errno = e; + return -1; + } + } + if (!feof(f_old)) { + e = errno; + fclose(f_old); + fclose(f_new); + errno = e; + return -1; + } + if (fclose(f_new) == EOF) { + e = errno; + fclose(f_old); + errno = e; + return -1; + } + fclose(f_old); + return 0; +#ifdef SYMLINKS + } +#endif +} int equivalent(lname, rname) char *lname; @@ -163,10 +227,10 @@ int equivalent(lname, rname) char *s; if (!strcmp(lname, rname)) - return 1; + return 1; for (s = lname; *s && (s = strchr(s, '/')); s++) { - while (s[1] == '/') - strcpy(s+1, s+2); + while (s[1] == '/') + strcpy(s+1, s+2); } return !strcmp(lname, rname); } @@ -176,10 +240,10 @@ int equivalent(lname, rname) directory. Assumes that files described by fs and ts are directories. */ dodir (fn, fs, ts, rel) -char *fn; /* name of "from" directory, either absolute or - relative to cwd */ -struct stat *fs, *ts; /* stats for the "from" directory and cwd */ -int rel; /* if true, prepend "../" to fn before using */ +char *fn; /* name of "from" directory, either absolute or + relative to cwd */ +struct stat *fs, *ts; /* stats for the "from" directory and cwd */ +int rel; /* if true, prepend "../" to fn before using */ { DIR *df; struct dirent *dp; @@ -188,136 +252,152 @@ int rel; /* if true, prepend "../" to fn before using */ char basesym[MAXPATHLEN + 1]; struct stat sb, sc; int n_dirs; - int symlen; + int symlen = -1; 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 ((fs->st_dev == ts->st_dev) && + (fs->st_ino == ts->st_ino) && + /* inode is always 0 on Windows; we don't want to fail in that case */ + (fs->st_ino != 0) + ) { + msg ("%s: From and to directories are identical!", fn); + return 1; } if (rel) - strcpy (buf, "../"); + strcpy (buf, "../"); else - buf[0] = '\0'; + buf[0] = '\0'; strcat (buf, fn); if (!(df = opendir (buf))) { - msg ("%s: Cannot opendir", buf); - return 1; + msg ("%s: Cannot opendir", buf); + return 1; } p = buf + strlen (buf); *p++ = '/'; n_dirs = fs->st_nlink; while (dp = readdir (df)) { - if (dp->d_name[strlen(dp->d_name) - 1] == '~') - continue; - if (dp->d_name[0] == '.' && dp->d_name[1] == '#') /* 'non-conflict files' left behind by CVS */ - continue; - strcpy (p, dp->d_name); - - if (n_dirs > 0) { - if (stat (buf, &sb) < 0) { - mperror (buf); - continue; - } + if (dp->d_name[strlen(dp->d_name) - 1] == '~') + continue; + if (dp->d_name[0] == '.' && dp->d_name[1] == '#') /* 'non-conflict files' left behind by CVS */ + continue; + strcpy (p, dp->d_name); + + if ( +#ifdef BELIEVE_ST_NLINK + n_dirs > 0 +#else + /* st_nlink is 1 on Windows, so we have to keep looking for + * directories forever */ + 1 +#endif + ) { + if (stat (buf, &sb) < 0) { + mperror (buf); + continue; + } #ifdef S_ISDIR - if(S_ISDIR(sb.st_mode)) + if(S_ISDIR(sb.st_mode)) #else - if (sb.st_mode & S_IFDIR) + if (sb.st_mode & S_IFDIR) #endif - { - /* directory */ + { + /* directory */ #ifndef __CYGWIN32__ /* don't trust cygwin's n_dirs count */ - n_dirs--; + n_dirs--; +#endif + if (dp->d_name[0] == '.' && + (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && + dp->d_name[2] == '\0'))) + 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, ".svn")) + continue; + if (!strcmp (dp->d_name, "_darcs")) + continue; + if (!strcmp (dp->d_name, "CVS.adm")) + 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 (mymkdir (dp->d_name, 0777) < 0 || + stat (dp->d_name, &sc) < 0) { + mperror (dp->d_name); + curdir = rcurdir = ocurdir; + continue; + } + } +#ifdef SYMLINKS + 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; + } #endif - if (dp->d_name[0] == '.' && - (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && - dp->d_name[2] == '\0'))) - 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, ".svn")) - continue; - if (!strcmp (dp->d_name, "_darcs")) - continue; - if (!strcmp (dp->d_name, "CVS.adm")) - 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; - } - } - - /* non-directory */ - symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1); - if (symlen >= 0) - symbuf[symlen] = '\0'; - - /* The option to ignore links exists mostly because - checking for them slows us down by 10-20%. - But it is off by default because this really is a useful check. */ - if (!ignore_links) { - /* see if the file in the base tree was a symlink */ - basesymlen = readlink(buf, basesym, sizeof(basesym) - 1); - if (basesymlen >= 0) - basesym[basesymlen] = '\0'; - } - - if (symlen >= 0) { - if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf)) { - if (force) { - unlink(dp->d_name); - if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0) - mperror (dp->d_name); - } else { - /* Link exists in new tree. Print message if it doesn't match. */ - msg ("%s: %s", dp->d_name, symbuf); - } - } - } else { - if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0) - mperror (dp->d_name); - } + if (chdir (dp->d_name) < 0) { + mperror (dp->d_name); + curdir = rcurdir = ocurdir; + continue; + } + rel = (fn[0] != '/') && ((fn[0] == '\0') || (fn[1] != ':')); + dodir (buf, &sb, &sc, rel); + if (chdir ("..") < 0) + quiterr (1, ".."); + curdir = rcurdir = ocurdir; + continue; + } + } + + /* non-directory */ +#ifdef SYMLINKS + symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1); + if (symlen >= 0) + symbuf[symlen] = '\0'; + + /* The option to ignore links exists mostly because + checking for them slows us down by 10-20%. + But it is off by default because this really is a useful check. */ + if (!ignore_links) { + /* see if the file in the base tree was a symlink */ + basesymlen = readlink(buf, basesym, sizeof(basesym) - 1); + if (basesymlen >= 0) + basesym[basesymlen] = '\0'; + } +#endif + + if (symlen >= 0) { + if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf)) { + if (force) { + unlink(dp->d_name); + if (copyfile (basesymlen>=0 ? basesym : buf, dp->d_name) < 0) + mperror (dp->d_name); + } else { + /* Link exists in new tree. Print message if it doesn't match. */ + msg ("%s: %s", dp->d_name, symbuf); + } + } + } else { + if (copyfile (basesymlen>=0 ? basesym : buf, dp->d_name) < 0) + mperror (dp->d_name); + } } closedir (df); return 0; } - main (ac, av) int ac; char **av; @@ -340,21 +420,23 @@ char **av; while (++av, --ac) { if (strcmp(*av, "-silent") == 0) - silent = 1; + silent = 1; else if (strcmp(*av, "-f") == 0) - force = 1; + force = 1; else if (strcmp(*av, "-ignorelinks") == 0) - ignore_links = 1; + ignore_links = 1; + else if (strcmp(*av, "-copy") == 0) + copy = 1; else if (strcmp(*av, "--") == 0) { - ++av, --ac; - break; + ++av, --ac; + break; } else - break; + break; } if (ac < 1 || ac > 2) - quit (1, "usage: %s [-f] [-silent] [-ignorelinks] fromdir [todir]", - prog_name); + quit (1, "usage: %s [-f] [-silent] [-ignorelinks] fromdir [todir]", + prog_name); #ifdef __CYGWIN32__ cygwin_conv_to_full_posix_path(av[0], fn); @@ -363,37 +445,37 @@ char **av; #endif if (ac == 2) - tn = av[1]; + tn = av[1]; else - tn = "."; + tn = "."; /* to directory */ if (stat (tn, &ts) < 0) { if (force && (tn[0] != '.' || tn[1] != '\0') ) { - mkdir(tn, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); + mymkdir(tn, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); } else { - quiterr (1, tn); + 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); + quit (2, "%s: Not a directory", tn); } } if (chdir (tn) < 0) - quiterr (1, tn); + quiterr (1, tn); /* from directory */ if (stat (fn, &fs) < 0) - quiterr (1, fn); + 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); + quit (2, "%s: Not a directory", fn); exit (dodir (fn, &fs, &ts, 0)); }