find.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * find.c - locate and optionally perform operations on files.
  3. * The author says this is only partly done, but I don't know what is missing.
  4. * But one thing that is certainly a bug is the existence of
  5. * MAXNAMELEN and MAXPATHLEN.
  6. */
  7. #include <stdio.h>
  8. #include <sys/types.h> /* typedefs */
  9. #include <sys/stat.h> /* structure returned by stat */
  10. #ifdef HP-UX
  11. #include <ndir.h> /* BSD directory entry structure */
  12. #else
  13. #include <dir.h> /* directory entry structure */
  14. #endif
  15. #define MAXPATHLEN 256
  16. #define MAXNAMELEN 256
  17. #define TRUE 1
  18. #define FALSE 0
  19. #define VALID 1
  20. #define INVALID 0
  21. #define MIN_NODES 20
  22. extern DIR *opendir();
  23. extern struct direct *readdir();
  24. extern long telldir();
  25. extern void seekdir();
  26. extern void closedir();
  27. extern char *malloc();
  28. void ScanDir();
  29. struct fnode *GetNode();
  30. typedef unsigned char bool;
  31. struct fnode {
  32. struct fnode *next;
  33. char name[MAXNAMELEN];
  34. };
  35. struct fnode *avail_head = NULL;
  36. int numpaths; /* Number of paths to search */
  37. int Argc; /* Global argc for functions */
  38. char **Argv; /* Global argv for functions */
  39. int max_nodes_avail = 0;
  40. int nodes_used = 0;
  41. int nodes_freed = 0;
  42. main (argc, argv)
  43. int argc;
  44. char *argv[];
  45. {
  46. int i; /* general purpose index */
  47. int pathindex; /* argv[pathindex] = current path */
  48. char buf[MAXPATHLEN]; /* buffer to contain current path */
  49. /* Validate Usage */
  50. if (argc < 2) {
  51. fprintf(stderr,"Usage: find path-list predicate-list\n");
  52. exit(1);
  53. }
  54. /* Make argv and argc global for other functions */
  55. Argc = argc;
  56. Argv = argv;
  57. /* Parse Arguments and Validate */
  58. if (! ParseArguments()) {
  59. fprintf(stderr,"find: parsing error\n");
  60. exit(1);
  61. }
  62. /* Refresh the pool used to contain unevaluated directory entrys */
  63. RefreshPool();
  64. /* Descend argv[1] through argv[numpaths] */
  65. for (pathindex = 1; pathindex <= numpaths; pathindex++) {
  66. for (i = 0; i < sizeof (buf); i++)
  67. buf[i] = '\0';
  68. strcpy(buf,argv[pathindex]);
  69. ScanDir(buf);
  70. }
  71. /* Print statistics */
  72. printf("\n\n\n");
  73. printf("Max nodes avail: %d\n",max_nodes_avail);
  74. printf("Nodes used: %d\n",nodes_used);
  75. printf("Nodes freed: %d\n",nodes_freed);
  76. }
  77. /*
  78. * Parse Arguments - calculate number of paths in path-list and compile
  79. * arguments into a linked list of functions to be
  80. * applied to each visited node.
  81. *
  82. * side effects: global variable "numpaths" = numpaths to search.
  83. *
  84. * returns: VALID = argument list is valid
  85. * INVALID = invalid argument list
  86. */
  87. int
  88. ParseArguments()
  89. {
  90. /* Calculate the number of paths in the path list */
  91. numpaths = Argc - 1;
  92. return VALID;
  93. }
  94. /*
  95. * RefreshPool - keep a minimum number of nodes to remember directory in.
  96. */
  97. int
  98. RefreshPool()
  99. {
  100. struct fnode *anode;
  101. int i;
  102. for (i = 0; i < MIN_NODES; i++) {
  103. anode = (struct fnode *) malloc(sizeof(struct fnode));
  104. anode->next = avail_head;
  105. avail_head = anode;
  106. }
  107. max_nodes_avail += MIN_NODES;
  108. }
  109. /*
  110. * GetNode - acquire a node to save directory's file names in during descent.
  111. */
  112. struct fnode
  113. *GetNode()
  114. {
  115. struct fnode *ap;
  116. if (avail_head == NULL)
  117. RefreshPool();
  118. ap = avail_head;
  119. avail_head = avail_head->next;
  120. ap->next = NULL;
  121. nodes_used++;
  122. return ap;
  123. }
  124. /*
  125. * FreeNode - return file node to pool.
  126. */
  127. void
  128. FreeNode(nodeptr)
  129. struct fnode *nodeptr;
  130. {
  131. nodeptr->next = avail_head;
  132. avail_head = nodeptr;
  133. nodes_freed++;
  134. }
  135. /*
  136. * ScanDir - scan the named directory and if file matches search criteria
  137. * apply any specified operations to it.
  138. */
  139. void
  140. ScanDir(name)
  141. char *name;
  142. {
  143. struct direct dirbuf, *dp = &dirbuf;
  144. DIR *d;
  145. struct fnode anode, *ap, *list_head, *trailp;
  146. struct stat filestat;
  147. /* If we cannot open this directory, ignore it */
  148. if ((d = opendir(name)) == NULL) {
  149. printf("Cannot open directory: %s\n",name);
  150. return;
  151. }
  152. /* Change directories to requested directory */
  153. chdir(name);
  154. /* Obtain the head of the linked list of directory entries */
  155. list_head = GetNode();
  156. ap = list_head;
  157. /* Build a list of all of the relevant entries within this directory */
  158. for (dp = readdir(d); dp != NULL; dp = readdir(d)) {
  159. /* skip the current directory and its parent */
  160. if ( (strcmp(dp->d_name,".") == 0) || (strcmp(dp->d_name,"..") == 0) )
  161. continue;
  162. strcpy(ap->name,dp->d_name);
  163. trailp = ap;
  164. ap = GetNode();
  165. trailp->next = ap;
  166. }
  167. /* We've saved a copy of all the entries in this directory */
  168. closedir(d);
  169. /* Perform processing for all files within this directory */
  170. for (ap=list_head;ap->next!=NULL;trailp=ap->next,FreeNode(ap),ap=trailp) {
  171. /* Get file status */
  172. if (stat(ap->name, &filestat) == -1) {
  173. fprintf(stderr, "newfind: can't find %s\n", ap->name);
  174. return;
  175. }
  176. /* Print the size of this file */
  177. printf("Visiting: %8ld %s/%s\n", filestat.st_size, name,ap->name);
  178. /* If file is a directory, descend */
  179. if (filestat.st_mode & S_IFDIR) {
  180. DIR *subd; /* sub-directory */
  181. char cwd[MAXPATHLEN+1]; /* current working directory */
  182. chdir(ap->name);
  183. if ((subd = opendir(".")) == NULL) {
  184. printf("cannot open directory: %s\n",ap->name);
  185. exit(-1);
  186. }
  187. getwd(cwd);
  188. closedir(subd);
  189. ScanDir(cwd);
  190. chdir("..");
  191. }
  192. }
  193. /* Free the unused trailing node on the list */
  194. FreeNode(ap);
  195. }