PageRenderTime 64ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/utils/lndir/lndir.c

https://github.com/dorchard/ghc
C | 485 lines | 380 code | 41 blank | 64 comment | 104 complexity | b752ed2bd28f4e0b17a87b5bc2614a17 MD5 | raw file
  1. /* $XConsortium: lndir.c /main/16 1996/09/28 16:16:40 rws $ */
  2. /* Create shadow link tree (after X11R4 script of the same name)
  3. Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990 */
  4. /*
  5. Copyright (c) 1990, X Consortium
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  18. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  19. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20. Except as contained in this notice, the name of the X Consortium shall not be
  21. used in advertising or otherwise to promote the sale, use or other dealings
  22. in this Software without prior written authorization from the X Consortium.
  23. */
  24. /* From the original /bin/sh script:
  25. Used to create a copy of the a directory tree that has links for all
  26. non-directories (except those named RCS, SCCS or CVS.adm). If you are
  27. building the distribution on more than one machine, you should use
  28. this technique.
  29. If your master sources are located in /usr/local/src/X and you would like
  30. your link tree to be in /usr/local/src/new-X, do the following:
  31. % mkdir /usr/local/src/new-X
  32. % cd /usr/local/src/new-X
  33. % lndir ../X
  34. */
  35. #define NeedVarargsPrototypes 1
  36. #include "lndir-Xos.h"
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <sys/stat.h>
  40. #include <sys/param.h>
  41. #include <errno.h>
  42. #ifndef X_NOT_POSIX
  43. #include <dirent.h>
  44. #else
  45. #ifdef SYSV
  46. #include <dirent.h>
  47. #else
  48. #ifdef USG
  49. #include <dirent.h>
  50. #else
  51. #include <sys/dir.h>
  52. #ifndef dirent
  53. #define dirent direct
  54. #endif
  55. #endif
  56. #endif
  57. #endif
  58. #ifndef MAXPATHLEN
  59. #define MAXPATHLEN 2048
  60. #endif
  61. #ifdef __CYGWIN32__
  62. #include <sys/cygwin.h>
  63. #endif
  64. #if NeedVarargsPrototypes
  65. #include <stdarg.h>
  66. #endif
  67. #ifdef X_NOT_STDC_ENV
  68. extern int errno;
  69. #endif
  70. int silent = 0; /* -silent */
  71. int copy = 0; /* -copy */
  72. int ignore_links = 0; /* -ignorelinks */
  73. char *rcurdir;
  74. char *curdir;
  75. int force=0;
  76. #ifdef WIN32
  77. #define mymkdir(X, Y) mkdir(X)
  78. #else
  79. #define mymkdir(X, Y) mkdir(X, Y)
  80. #endif
  81. #ifndef WIN32
  82. #define SYMLINKS
  83. #define BELIEVE_ST_NLINK
  84. #endif
  85. void
  86. quit (
  87. #if NeedVarargsPrototypes
  88. int code, char * fmt, ...)
  89. #else
  90. code, fmt, a1, a2, a3)
  91. char *fmt;
  92. #endif
  93. {
  94. #if NeedVarargsPrototypes
  95. va_list args;
  96. va_start(args, fmt);
  97. vfprintf (stderr, fmt, args);
  98. va_end(args);
  99. #else
  100. fprintf (stderr, fmt, a1, a2, a3);
  101. #endif
  102. putc ('\n', stderr);
  103. exit (code);
  104. }
  105. void
  106. quiterr (code, s)
  107. char *s;
  108. {
  109. perror (s);
  110. exit (code);
  111. }
  112. void
  113. msg (
  114. #if NeedVarargsPrototypes
  115. char * fmt, ...)
  116. #else
  117. fmt, a1, a2, a3)
  118. char *fmt;
  119. #endif
  120. {
  121. #if NeedVarargsPrototypes
  122. va_list args;
  123. #endif
  124. if (curdir) {
  125. fprintf (stderr, "%s:\n", curdir);
  126. curdir = 0;
  127. }
  128. #if NeedVarargsPrototypes
  129. va_start(args, fmt);
  130. vfprintf (stderr, fmt, args);
  131. va_end(args);
  132. #else
  133. fprintf (stderr, fmt, a1, a2, a3);
  134. #endif
  135. putc ('\n', stderr);
  136. }
  137. void
  138. mperror (s)
  139. char *s;
  140. {
  141. if (curdir) {
  142. fprintf (stderr, "%s:\n", curdir);
  143. curdir = 0;
  144. }
  145. perror (s);
  146. }
  147. #define BUFSIZE 1024
  148. int copyfile(const char *oldpath, const char *newpath) {
  149. FILE *f_old;
  150. FILE *f_new;
  151. int e;
  152. ssize_t s;
  153. char buf[BUFSIZE];
  154. #ifdef SYMLINKS
  155. if (copy == 0) {
  156. return symlink(oldpath, newpath);
  157. } else {
  158. #endif
  159. f_old = fopen(oldpath, "rb");
  160. if (f_old == NULL) {
  161. return -1;
  162. }
  163. f_new = fopen(newpath, "wbx");
  164. if (f_new == NULL) {
  165. e = errno;
  166. fclose(f_old);
  167. errno = e;
  168. return -1;
  169. }
  170. while ((s = fread(buf, 1, BUFSIZE, f_old)) > 0) {
  171. if (fwrite(buf, 1, s, f_new) < s) {
  172. e = errno;
  173. fclose(f_old);
  174. fclose(f_new);
  175. errno = e;
  176. return -1;
  177. }
  178. }
  179. if (!feof(f_old)) {
  180. e = errno;
  181. fclose(f_old);
  182. fclose(f_new);
  183. errno = e;
  184. return -1;
  185. }
  186. if (fclose(f_new) == EOF) {
  187. e = errno;
  188. fclose(f_old);
  189. errno = e;
  190. return -1;
  191. }
  192. fclose(f_old);
  193. return 0;
  194. #ifdef SYMLINKS
  195. }
  196. #endif
  197. }
  198. int equivalent(lname, rname)
  199. char *lname;
  200. char *rname;
  201. {
  202. char *s;
  203. if (!strcmp(lname, rname))
  204. return 1;
  205. for (s = lname; *s && (s = strchr(s, '/')); s++) {
  206. while (s[1] == '/')
  207. strcpy(s+1, s+2);
  208. }
  209. return !strcmp(lname, rname);
  210. }
  211. /* Recursively create symbolic links from the current directory to the "from"
  212. directory. Assumes that files described by fs and ts are directories. */
  213. dodir (fn, fs, ts, rel)
  214. char *fn; /* name of "from" directory, either absolute or
  215. relative to cwd */
  216. struct stat *fs, *ts; /* stats for the "from" directory and cwd */
  217. int rel; /* if true, prepend "../" to fn before using */
  218. {
  219. DIR *df;
  220. struct dirent *dp;
  221. char buf[MAXPATHLEN + 1], *p;
  222. char symbuf[MAXPATHLEN + 1];
  223. char basesym[MAXPATHLEN + 1];
  224. struct stat sb, sc;
  225. int n_dirs;
  226. int symlen = -1;
  227. int basesymlen = -1;
  228. char *ocurdir;
  229. if ((fs->st_dev == ts->st_dev) &&
  230. (fs->st_ino == ts->st_ino) &&
  231. /* inode is always 0 on Windows; we don't want to fail in that case */
  232. (fs->st_ino != 0)
  233. ) {
  234. msg ("%s: From and to directories are identical!", fn);
  235. return 1;
  236. }
  237. if (rel)
  238. strcpy (buf, "../");
  239. else
  240. buf[0] = '\0';
  241. strcat (buf, fn);
  242. if (!(df = opendir (buf))) {
  243. msg ("%s: Cannot opendir", buf);
  244. return 1;
  245. }
  246. p = buf + strlen (buf);
  247. *p++ = '/';
  248. n_dirs = fs->st_nlink;
  249. while (dp = readdir (df)) {
  250. if (dp->d_name[strlen(dp->d_name) - 1] == '~')
  251. continue;
  252. if (dp->d_name[0] == '.' && dp->d_name[1] == '#') /* 'non-conflict files' left behind by CVS */
  253. continue;
  254. strcpy (p, dp->d_name);
  255. if (
  256. #ifdef BELIEVE_ST_NLINK
  257. n_dirs > 0
  258. #else
  259. /* st_nlink is 1 on Windows, so we have to keep looking for
  260. * directories forever */
  261. 1
  262. #endif
  263. ) {
  264. if (stat (buf, &sb) < 0) {
  265. mperror (buf);
  266. continue;
  267. }
  268. #ifdef S_ISDIR
  269. if(S_ISDIR(sb.st_mode))
  270. #else
  271. if (sb.st_mode & S_IFDIR)
  272. #endif
  273. {
  274. /* directory */
  275. #ifndef __CYGWIN32__ /* don't trust cygwin's n_dirs count */
  276. n_dirs--;
  277. #endif
  278. if (dp->d_name[0] == '.' &&
  279. (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
  280. dp->d_name[2] == '\0')))
  281. continue;
  282. if (!strcmp (dp->d_name, "RCS"))
  283. continue;
  284. if (!strcmp (dp->d_name, "SCCS"))
  285. continue;
  286. if (!strcmp (dp->d_name, "CVS"))
  287. continue;
  288. if (!strcmp (dp->d_name, ".svn"))
  289. continue;
  290. if (!strcmp (dp->d_name, ".git"))
  291. continue;
  292. if (!strcmp (dp->d_name, "_darcs"))
  293. continue;
  294. if (!strcmp (dp->d_name, "CVS.adm"))
  295. continue;
  296. ocurdir = rcurdir;
  297. rcurdir = buf;
  298. curdir = silent ? buf : (char *)0;
  299. if (!silent)
  300. printf ("%s:\n", buf);
  301. if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
  302. if (mymkdir (dp->d_name, 0777) < 0 ||
  303. stat (dp->d_name, &sc) < 0) {
  304. mperror (dp->d_name);
  305. curdir = rcurdir = ocurdir;
  306. continue;
  307. }
  308. }
  309. #ifdef SYMLINKS
  310. if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
  311. msg ("%s: is a link instead of a directory", dp->d_name);
  312. curdir = rcurdir = ocurdir;
  313. continue;
  314. }
  315. #endif
  316. if (chdir (dp->d_name) < 0) {
  317. mperror (dp->d_name);
  318. curdir = rcurdir = ocurdir;
  319. continue;
  320. }
  321. rel = (fn[0] != '/') && ((fn[0] == '\0') || (fn[1] != ':'));
  322. dodir (buf, &sb, &sc, rel);
  323. if (chdir ("..") < 0)
  324. quiterr (1, "..");
  325. curdir = rcurdir = ocurdir;
  326. continue;
  327. }
  328. }
  329. /* non-directory */
  330. #ifdef SYMLINKS
  331. symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
  332. if (symlen >= 0)
  333. symbuf[symlen] = '\0';
  334. /* The option to ignore links exists mostly because
  335. checking for them slows us down by 10-20%.
  336. But it is off by default because this really is a useful check. */
  337. if (!ignore_links) {
  338. /* see if the file in the base tree was a symlink */
  339. basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
  340. if (basesymlen >= 0)
  341. basesym[basesymlen] = '\0';
  342. }
  343. #endif
  344. if (symlen >= 0) {
  345. if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf)) {
  346. if (force) {
  347. unlink(dp->d_name);
  348. if (copyfile (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
  349. mperror (dp->d_name);
  350. } else {
  351. /* Link exists in new tree. Print message if it doesn't match. */
  352. msg ("%s: %s", dp->d_name, symbuf);
  353. }
  354. }
  355. } else {
  356. if (copyfile (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
  357. mperror (dp->d_name);
  358. }
  359. }
  360. closedir (df);
  361. return 0;
  362. }
  363. main (ac, av)
  364. int ac;
  365. char **av;
  366. {
  367. char *prog_name = av[0];
  368. char* tn;
  369. struct stat fs, ts;
  370. #ifdef __CYGWIN32__
  371. /*
  372. The lndir code assumes unix-style paths to work. cygwin
  373. lets you get away with using dos'ish paths (e.g., "f:/oo")
  374. in most contexts. Using them with 'lndir' will seriously
  375. confuse the user though, so under-the-hood, we convert the
  376. path into something POSIX-like.
  377. */
  378. static char fn[MAXPATHLEN+1];
  379. #else
  380. char *fn;
  381. #endif
  382. while (++av, --ac) {
  383. if (strcmp(*av, "-silent") == 0)
  384. silent = 1;
  385. else if (strcmp(*av, "-f") == 0)
  386. force = 1;
  387. else if (strcmp(*av, "-ignorelinks") == 0)
  388. ignore_links = 1;
  389. else if (strcmp(*av, "-copy") == 0)
  390. copy = 1;
  391. else if (strcmp(*av, "--") == 0) {
  392. ++av, --ac;
  393. break;
  394. } else
  395. break;
  396. }
  397. if (ac < 1 || ac > 2)
  398. quit (1, "usage: %s [-f] [-silent] [-ignorelinks] fromdir [todir]",
  399. prog_name);
  400. #ifdef __CYGWIN32__
  401. cygwin_conv_to_full_posix_path(av[0], fn);
  402. #else
  403. fn = av[0];
  404. #endif
  405. if (ac == 2)
  406. tn = av[1];
  407. else
  408. tn = ".";
  409. /* to directory */
  410. if (stat (tn, &ts) < 0) {
  411. if (force && (tn[0] != '.' || tn[1] != '\0') ) {
  412. mymkdir(tn, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
  413. }
  414. else {
  415. quiterr (1, tn);
  416. #ifdef S_ISDIR
  417. if (!(S_ISDIR(ts.st_mode)))
  418. #else
  419. if (!(ts.st_mode & S_IFDIR))
  420. #endif
  421. quit (2, "%s: Not a directory", tn);
  422. }
  423. }
  424. if (chdir (tn) < 0)
  425. quiterr (1, tn);
  426. /* from directory */
  427. if (stat (fn, &fs) < 0)
  428. quiterr (1, fn);
  429. #ifdef S_ISDIR
  430. if (!(S_ISDIR(fs.st_mode)))
  431. #else
  432. if (!(fs.st_mode & S_IFDIR))
  433. #endif
  434. quit (2, "%s: Not a directory", fn);
  435. exit (dodir (fn, &fs, &ts, 0));
  436. }