link.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /* $Source: /u/mark/src/pax/RCS/link.c,v $
  2. *
  3. * $Revision: 1.2 $
  4. *
  5. * link.c - functions for handling multiple file links
  6. *
  7. * DESCRIPTION
  8. *
  9. * These function manage the link chains which are used to keep track
  10. * of outstanding links during archive reading and writing.
  11. *
  12. * AUTHOR
  13. *
  14. * Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
  15. *
  16. * Sponsored by The USENIX Association for public distribution.
  17. *
  18. * Copyright (c) 1989 Mark H. Colburn.
  19. * All rights reserved.
  20. *
  21. * Redistribution and use in source and binary forms are permitted
  22. * provided that the above copyright notice is duplicated in all such
  23. * forms and that any documentation, advertising materials, and other
  24. * materials related to such distribution and use acknowledge that the
  25. * software was developed * by Mark H. Colburn and sponsored by The
  26. * USENIX Association.
  27. *
  28. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  29. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  30. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  31. *
  32. * $Log: link.c,v $
  33. * Revision 1.2 89/02/12 10:04:38 mark
  34. * 1.2 release fixes
  35. *
  36. * Revision 1.1 88/12/23 18:02:12 mark
  37. * Initial revision
  38. *
  39. */
  40. #ifndef lint
  41. static char *ident = "$Id: link.c,v 1.2 89/02/12 10:04:38 mark Exp $";
  42. static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  43. #endif /* ! lint */
  44. /* Headers */
  45. #include "pax.h"
  46. /* Defines */
  47. /*
  48. * Address link information base.
  49. */
  50. #define LINKHASH(ino) (linkbase + (ino) % NEL(linkbase))
  51. /*
  52. * Number of array elements.
  53. */
  54. #define NEL(a) (sizeof(a) / sizeof(*(a)))
  55. /* Internal Identifiers */
  56. static Link *linkbase[256]; /* Unresolved link information */
  57. /* linkfrom - find a file to link from
  58. *
  59. * DESCRIPTION
  60. *
  61. * Linkfrom searches the link chain to see if there is a file in the
  62. * link chain which has the same inode number as the file specified
  63. * by the stat block pointed at by asb. If a file is found, the
  64. * name is returned to the caller, otherwise a NULL is returned.
  65. *
  66. * PARAMETERS
  67. *
  68. * char *name - name of the file which we are attempting
  69. * to find a link for
  70. * Stat *asb - stat structure of file to find a link to
  71. *
  72. * RETURNS
  73. *
  74. * Returns a pointer to a link structure, or NULL if unsuccessful.
  75. *
  76. */
  77. #ifdef __STDC__
  78. Link *linkfrom(char *name, Stat *asb)
  79. #else
  80. Link *linkfrom(name, asb)
  81. char *name;
  82. Stat *asb;
  83. #endif
  84. {
  85. Link *linkp;
  86. Link *linknext;
  87. Path *path;
  88. Path *pathnext;
  89. Link **abase;
  90. for (linkp = *(abase = LINKHASH(asb->sb_ino)); linkp; linkp = linknext) {
  91. if (linkp->l_nlink == 0) {
  92. if (linkp->l_name) {
  93. free((char *) linkp->l_name);
  94. }
  95. if (linknext = linkp->l_forw) {
  96. linknext->l_back = linkp->l_back;
  97. }
  98. if (linkp->l_back) {
  99. linkp->l_back->l_forw = linkp->l_forw;
  100. }
  101. free((char *) linkp);
  102. *abase = (Link *)NULL;
  103. } else if (linkp->l_ino == asb->sb_ino && linkp->l_dev == asb->sb_dev) {
  104. /*
  105. * check to see if a file with the name "name" exists in the
  106. * chain of files which we have for this particular link
  107. */
  108. for (path = linkp->l_path; path; path = pathnext) {
  109. if (strcmp(path->p_name, name) == 0) {
  110. --linkp->l_nlink;
  111. if (path->p_name) {
  112. free(path->p_name);
  113. }
  114. if (pathnext = path->p_forw) {
  115. pathnext->p_back = path->p_back;
  116. }
  117. if (path->p_back) {
  118. path->p_back->p_forw = pathnext;
  119. }
  120. if (linkp->l_path == path) {
  121. linkp->l_path = pathnext;
  122. }
  123. free(path);
  124. return (linkp);
  125. }
  126. pathnext = path->p_forw;
  127. }
  128. return((Link *)NULL);
  129. } else {
  130. linknext = linkp->l_forw;
  131. }
  132. }
  133. return ((Link *)NULL);
  134. }
  135. /* islink - determine whether a given file really a link
  136. *
  137. * DESCRIPTION
  138. *
  139. * Islink searches the link chain to see if there is a file in the
  140. * link chain which has the same inode number as the file specified
  141. * by the stat block pointed at by asb. If a file is found, a
  142. * non-zero value is returned to the caller, otherwise a 0 is
  143. * returned.
  144. *
  145. * PARAMETERS
  146. *
  147. * char *name - name of file to check to see if it is link.
  148. * Stat *asb - stat structure of file to find a link to
  149. *
  150. * RETURNS
  151. *
  152. * Returns a pointer to a link structure, or NULL if unsuccessful.
  153. *
  154. */
  155. #ifdef __STDC__
  156. Link *islink(char *name, Stat *asb)
  157. #else
  158. Link *islink(name, asb)
  159. char *name;
  160. Stat *asb;
  161. #endif
  162. {
  163. Link *linkp;
  164. Link *linknext;
  165. for (linkp = *(LINKHASH(asb->sb_ino)); linkp; linkp = linknext) {
  166. if (linkp->l_ino == asb->sb_ino && linkp->l_dev == asb->sb_dev) {
  167. if (strcmp(name, linkp->l_name) == 0) {
  168. return ((Link *)NULL);
  169. }
  170. return (linkp);
  171. } else {
  172. linknext = linkp->l_forw;
  173. }
  174. }
  175. return ((Link *)NULL);
  176. }
  177. /* linkto - remember a file with outstanding links
  178. *
  179. * DESCRIPTION
  180. *
  181. * Linkto adds the specified file to the link chain. Any subsequent
  182. * calls to linkfrom which have the same inode will match the file
  183. * just entered. If not enough space is available to make the link
  184. * then the item is not added to the link chain, and a NULL is
  185. * returned to the calling function.
  186. *
  187. * PARAMETERS
  188. *
  189. * char *name - name of file to remember
  190. * Stat *asb - pointer to stat structure of file to remember
  191. *
  192. * RETURNS
  193. *
  194. * Returns a pointer to the associated link structure, or NULL when
  195. * linking is not possible.
  196. *
  197. */
  198. #ifdef __STDC__
  199. Link *linkto(char *name, Stat *asb)
  200. #else
  201. Link *linkto(name, asb)
  202. char *name;
  203. Stat *asb;
  204. #endif
  205. {
  206. Link *linkp;
  207. Link *linknext;
  208. Path *path;
  209. Link **abase;
  210. for (linkp = *(LINKHASH(asb->sb_ino)); linkp; linkp = linknext) {
  211. if (linkp->l_ino == asb->sb_ino && linkp->l_dev == asb->sb_dev) {
  212. if ((path = (Path *) mem_get(sizeof(Path))) == (Path *)NULL ||
  213. (path->p_name = mem_str(name)) == (char *)NULL) {
  214. return((Link *)NULL);
  215. }
  216. if (path->p_forw = linkp->l_path) {
  217. if (linkp->l_path->p_forw) {
  218. linkp->l_path->p_forw->p_back = path;
  219. }
  220. } else {
  221. linkp->l_path = path;
  222. }
  223. path->p_back = (Path *)NULL;
  224. return(linkp);
  225. } else {
  226. linknext = linkp->l_forw;
  227. }
  228. }
  229. /*
  230. * This is a brand new link, for which there is no other information
  231. */
  232. if ((asb->sb_mode & S_IFMT) == S_IFDIR
  233. || (linkp = (Link *) mem_get(sizeof(Link))) == (Link *)NULL
  234. || (linkp->l_name = mem_str(name)) == (char *)NULL) {
  235. return ((Link *)NULL);
  236. }
  237. linkp->l_dev = asb->sb_dev;
  238. linkp->l_ino = asb->sb_ino;
  239. linkp->l_nlink = asb->sb_nlink - 1;
  240. linkp->l_size = asb->sb_size;
  241. linkp->l_path = (Path *)NULL;
  242. if (linkp->l_forw = *(abase = LINKHASH(asb->sb_ino))) {
  243. linkp->l_forw->l_back = linkp;
  244. } else {
  245. *abase = linkp;
  246. }
  247. linkp->l_back = (Link *)NULL;
  248. return (linkp);
  249. }
  250. /* linkleft - complain about files with unseen links
  251. *
  252. * DESCRIPTION
  253. *
  254. * Linksleft scans through the link chain to see if there were any
  255. * files which have outstanding links that were not processed by the
  256. * archive. For each file in the link chain for which there was not
  257. * a file, and error message is printed.
  258. */
  259. #ifdef __STDC__
  260. void linkleft(void)
  261. #else
  262. void linkleft()
  263. #endif
  264. {
  265. Link *lp;
  266. Link **base;
  267. for (base = linkbase; base < linkbase + NEL(linkbase); ++base) {
  268. for (lp = *base; lp; lp = lp->l_forw) {
  269. if (lp->l_nlink) {
  270. warn(lp->l_path->p_name, "Unseen link(s)");
  271. }
  272. }
  273. }
  274. }