source: trunk/athena/bin/delete/pattern.c @ 23667

Revision 23667, 26.3 KB checked in by broder, 15 years ago (diff)
In delete: * Apply patches from jik: - When adding to an array, leave some extra space at the end so that we don't have to keep growing it every time.
RevLine 
[1691]1/*
[12350]2 * $Id: pattern.c,v 1.28 1999-01-22 23:09:03 ghudson Exp $
[1691]3 *
4 * This program is part of a package including delete, undelete,
5 * lsdel, expunge and purge.  The software suite is meant as a
6 * replacement for rm which allows for file recovery.
7 *
8 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
[4505]9 * For copying and distribution information, see the file "mit-copying.h."
[1691]10 */
11
12#if (!defined(lint) && !defined(SABER))
[12350]13     static char rcsid_pattern_c[] = "$Id: pattern.c,v 1.28 1999-01-22 23:09:03 ghudson Exp $";
[1691]14#endif
15
16#include <stdio.h>
17#include <sys/types.h>
[5048]18#include <dirent.h>
[1691]19#include <sys/param.h>
[3049]20#include <string.h>
[2175]21#include <errno.h>
22#include <com_err.h>
[1691]23#include "pattern.h"
24#include "util.h"
[4415]25#include "directories.h"
[1691]26#include "undelete.h"
[2175]27#include "shell_regexp.h"
[4505]28#include "mit-copying.h"
[2175]29#include "delete_errs.h"
30#include "errors.h"
[2221]31#include "stack.h"
[1691]32
[2175]33extern char *whoami;
[1691]34
[2221]35void free_list();
[1691]36
37
38/*
39 * add_arrays() takes pointers to two arrays of char **'s and their
40 * lengths, merges the two into the first by realloc'ing the first and
41 * then free's the second's memory usage.
42 */ 
[23667]43int add_arrays(array1, num1, size1, array2, num2)
[1691]44char ***array1, ***array2;
[23667]45int *num1, *size1, *num2;
[1691]46{
47     int counter;
[23667]48
49     if (! *size1) {
50       if (*array1)
51         free(*array1);
52       *array1 = *array2;
53       *num1 = *num2;
54       *size1 = *num2;
55       return 0;
56     }
57
58     while (*size1 < (*num1 + *num2)) {
59       *size1 *= 2;
60     }
61
[2175]62     *array1 = (char **) realloc((char *) *array1, (unsigned)
[23667]63                                 (sizeof(char *) * *size1));
64     if (! *array1) {
[2175]65          set_error(errno);
66          error("realloc");
67          return error_code;
[1691]68     }
69     for (counter = *num1; counter < *num1 + *num2; counter++)
70          *(*array1 + counter) = *(*array2 + counter - *num1);
[2175]71     free ((char *) *array2);
[1691]72     *num1 += *num2;
[2175]73     return 0;
[1691]74}
75
76
77
78
[1705]79
80
[2175]81/*
82 * Add a string to a list of strings.
83 */
[23667]84int add_str(strs, num, size, str)
[2175]85char ***strs;
[23667]86int num, *size;
[1705]87char *str;
88{
[2175]89     char **ary;
90
[23667]91     if (! *size) {
92       num = 0;
93       *size = 1;
94       ary = *strs = (char **) malloc((unsigned) (sizeof(char *)));
95     }
96     else if (num == *size) {
97       *size *= 2;
98       ary = *strs = (char **) realloc((char *) *strs, (unsigned)
99                                       (sizeof(char *) * *size));
100     }
101     else {
102       ary = *strs;
103     }
104
[2221]105     if (! *strs) {
[2175]106          set_error(errno);
107          error("realloc");
108          return error_code;
[1705]109     }
[2365]110     ary[num] = Malloc((unsigned) (strlen(str) + 1));
[2175]111     if (! ary[num]) {
112          set_error(errno);
[2365]113          error("Malloc");
[2175]114          return error_code;
[1705]115     }
[2175]116     (void) strcpy(ary[num], str);
117     return 0;
[1705]118}
119
120
121
122
123
[2221]124/*
125 * Find_matches will behave unpredictably if you try to use it to find
126 * very strange combinations of file types, for example only searching
127 * for undeleted files in the top-level directory, while searching
128 * recursively for deleted files.  Basically, there are some conflicts
129 * between options that I don't list here because I don't think I'll
130 * ever need to use those combinations.
131 */
132/*
133 * Function: find_matches(char *name, int *num_found, char ***found,
134 *                        int options)
135 *
136 * Requires: name points to a NULL-terminated string, representing a
137 *   filename pattern with regular filename characters, path
138 *   separators and shell wildcard characters []*?; num_found points
139 *   to a valid int memory storage location; found points to a valid
140 *   char ** memory storage location.
141 *
142 * Effects: Returns a list of all the files in the file hierarchy that
143 *   match the options specified in options and that match name.
144 *   Options are:
145 *
146 *   FIND_UNDELETED search for and return undeleted files
147 *
148 *   FIND_DELETED search for and return deleted files
149 *
150 *   FIND_CONTENTS means that if matches are directories (or links to
151 *     directories), the contents of the directory should be matched
152 *     in addition to the directory itself
153 *
154 *   RECURS_FIND_DELETED to search all undeleted subdirectories
155 *     recursively of matched directories looking for deleted files
156 *
157 *   RECURS_FIND_UNDELETED to search all undeleted subdirectories
158 *     recursively of matched directories looking for undeleted files
159 *
160 *   RECURS_DELETED to recursively return all contents of deleted
161 *     directories in addition to the directories themselves
162 *   
163 *   FOLLW_LINKS to pursue symlinks to directories and continue down
164 *     the referenced directories when searching recursively (if the
165 *     initial string is an undeleted symlink it is always traversed;
166 *     deleted symlinks are never traversed)
167 *   
168 *   FOLLW_MOUNTPOINTS to traverse mount points when searching
169 *     recursively (if the initial string is a mountpoint it is always
170 *     traversed)
171 *
172 *   FIND_DOTFILES forces the system to recognize dot files instead of
173 *     discarding them when looking for files
174 *
175 *   If the first character of name is '/', the search is conducted
176 *   absolutely from the root of the hierarchy; else, it is conducted
177 *   relative to the current working directory.  The number of
178 *   matching files is returned in *num_found, and a list of file
179 *   names is returned in *found.  If there are no errors, the return
180 *   value is 0; else the return value represents the error code of
181 *   the error which occurred.  No matter how many file names are
182 *   returned, the memory location addressed in *found is a valid
[2365]183 *   pointer according to Malloc() and can be released using free()
[2221]184 *   safely.  However, if an error value is returned, the caller
185 *   should not attempt to use the values stored in *num_found or
186 *   *found.
187 *
188 * Modifies: *num_found, *found.
189 */
190int find_matches(name, num_found, found, options)
191char *name;
[1691]192int *num_found;
[2175]193char ***found;
[2221]194int options;
[1691]195{
[2221]196     char       **matched_files, **return_files, **recurs_files;
197     int        num_matched_files = 0, num_return_files = 0,
[23667]198                num_recurs_files = 0, return_files_size = 0;
[2221]199     int        retval;
200     int        i;
[2377]201#ifdef DEBUG
202     int        j;
203#endif
[2221]204     int        match_options = 0;
205
[2377]206#ifdef DEBUG
207     fprintf(stderr, "Entering find_matches, name = %s, options = %d.\n",
208             name, options);
209#endif
210     
[2221]211     match_options = options & (FIND_DELETED | FIND_UNDELETED);
212     if (options & (RECURS_FIND_DELETED | RECURS_FIND_UNDELETED |
213                    FIND_CONTENTS))
214          match_options |= FIND_UNDELETED;
[2175]215     
[2221]216     if (! match_options) {
217          set_error(PAT_NO_FILES_REQUESTED);
218          error("find_matches");
[2175]219          return error_code;
220     }
[2221]221     
222     retval = do_match(name, &num_matched_files, &matched_files,
223                       match_options & FIND_UNDELETED,
224                       match_options & FIND_DELETED);
225     if (retval) {
226          error(name);
227          return retval;
[2175]228     }
[2221]229     if (num_matched_files == 0) {
230          *num_found = num_matched_files;
231          *found = matched_files;
[2377]232#ifdef DEBUG
233          fprintf(stderr, "No matches found, returning.\n");
234#endif
[2221]235          return 0;
236     }
[1705]237
[2377]238#ifdef DEBUG
239     fprintf(stderr, "The following matches were found:\n");
240     for (i = 0; i < num_matched_files; i++)
241          fprintf(stderr, "  %s\n", matched_files[i]);
242#endif
243     
[2221]244     if (options & RECURS) {
[2365]245          return_files = (char **) Malloc(0);
246          num_return_files = 0;
247
[2221]248          for (i = 0; i < num_matched_files; i++) {
249
250               retval = do_recurs(matched_files[i], &num_recurs_files,
251                                  &recurs_files, options);
252               if (retval) {
253                    error(matched_files[i]);
[2175]254                    return retval;
[1691]255               }
[2221]256
[2365]257               if (num_recurs_files) {
258                    retval = add_arrays(&return_files, &num_return_files,
[23667]259                                        &return_files_size, &recurs_files,
260                                        &num_recurs_files);
[2365]261                    if (retval) {
262                         error("add_arrays");
263                         return retval;
264                    }
[2377]265#ifdef DEBUG
266                    fprintf(stderr,
267                            "Just added the following to return_files:\n");
268                    for (j = num_return_files - num_recurs_files;
269                         j < num_return_files; j++)
270                         fprintf(stderr, "  %s\n", return_files[j]);
271#endif
[1691]272               }
[2365]273               
[2377]274               if (is_deleted(lastpart(matched_files[i]))) {
[2221]275                    if (options & FIND_DELETED) {
276                         retval = add_str(&return_files, num_return_files,
[23667]277                                          &return_files_size,
[2221]278                                          matched_files[i]);
279                         if (retval) {
[2175]280                              error("add_str");
281                              return retval;
282                         }
[2221]283                         num_return_files++;
[2377]284#ifdef DEBUG
285                         fprintf(stderr, "Just added %s to return_files.\n",
286                                 return_files[num_return_files-1]);
287#endif
[2175]288                    }
289               }
[2221]290               else if (options & FIND_UNDELETED) {
291                    retval = add_str(&return_files, num_return_files,
[23667]292                                     &return_files_size, matched_files[i]);
[2221]293                    if (retval) {
294                         error("add_str");
295                         return retval;
296                    }
297                    num_return_files++;
[2377]298#ifdef DEBUG
299                    fprintf(stderr, "Just added %s to return_files.\n",
300                            return_files[num_return_files-1]);
301#endif
[2221]302               }
[2175]303          }
[2221]304          free_list(matched_files, num_matched_files);
305          *num_found = num_return_files;
306          *found = return_files;
[1691]307     }
[2221]308     else {
309          *num_found = num_matched_files;
310          *found = matched_files;
311     }
312
[2175]313     return 0;
[1705]314}
315
316
317
318
[2221]319         
320         
321                   
322               
323#define string_push(str)\
324          strsize = strlen(str);\
325          retval = push(str, strsize);\
326          if (! retval)\
327               retval |= push(&strsize, sizeof(int));\
328          if (retval) {\
329               error("push");\
330               (void) popall();\
331               return retval;\
332          }
333#define string_pop(str)\
334          retval = pop(&strsize, sizeof(int));\
335          if (! retval)\
336               retval = pop(str, strsize);\
337          if (! retval)\
338               str[strsize] = '\0'
339         
340         
[1705]341
[2221]342
343
344
345/*
346 * Function: do_match(char *name, int *num_found, char ***found,
347 *                    Boolean match_undeleted, Boolean match_deleted)
348 *
349 * Requires: name points to a NULL-terminated string, representing a
350 *   filename pattern with regular filename characters, path
351 *   separators and shell wildcard characters []*?; num_found points
352 *   to a valid int memory storage location; found points to a valid
353 *   char ** memory storage location.
354 *
355 * Effects: Returns a list of all the files in the file hierarchy that
356 *   match name.  If match_undeleted is true, will return undeleted
357 *   files that match; if match_deleted is true, will return
358 *   deleted_files that match.  If the first character of name is '/',
359 *   the search is conducted absolutely from the root of the
360 *   hierarchy; else, it is conducted relative to the current working
361 *   directory.  The number of matching files is returned in
362 *   *num_found, and a list of file names is returned in *found.  If
363 *   there are no errors, the return value is 0; else the return value
364 *   represents the error code of the error which occurred.  No matter
365 *   how many file names are returned, the memory location addressed
[2365]366 *   in *found is a valid pointer according to Malloc() and can be
[2221]367 *   released using free() safely.  However, if an error value is
368 *   returned, the caller should not attempt to use the values stored
369 *   in *num_found or *found.
370 *
371 * Modifies: *num_found, *found.
372 *
373 * Algorithm:
374 *
375 * start:
376 *   base = "" or "/",
377 *   name = name or name + 1
378 *   initialze found and num_found
[2482]379 *   dirp = Opendir(base)
[2221]380 *   first = firstpart(name, rest) (assigns rest as side-effect)
381 *   if (! *first) {
382 *     add string to list if appropriate
383 *     return
384 *
385 * loop:
386 *   dp = readdir(dirp)
387 *   if (! dp) goto updir
388 *   compare dp->d_name to first -- match?
389 *     yes - goto downdir
390 *     no - are we looking for deleted and is dp->d_name deleted?
391 *       yes - compare undeleted dp->d_name to first -- match?
392 *         yes - goto downdir
393 *         no - goto loop
394 *       no - goto loop
395 *
396 * downdir:
397 *   save dirp, rest, first and base on stack
398 *   first = firstpart(rest, rest)
399 *   base = dp->d_name appended to base
400 *   is first an empty string?
401 *      yes - put back dirp, rest, first, base
402 *            goto loop
403 *   try to open dir base - opens?
404 *      yes - goto loop
405 *      no - is the error ENOTDIR?
406 *             yes - don't worry about it
407 *             no - report the error
408 *           restore dirp, rest, first, base from stack
409 *           goto loop
410 *
411 * updir:
412 *   close dirp
413 *   restore base, rest, first from stack
414 *   STACK_EMPTY?
415 *     yes - return from procedure with results
416 *   restore dirp from stack
417 *   goto loop
418 */
419int do_match(name, num_found, found, match_undeleted, match_deleted)
420char *name;
[1705]421int *num_found;
[2175]422char ***found;
[2221]423Boolean match_undeleted, match_deleted;
[1705]424{
[2221]425     char base[MAXPATHLEN];
[5138]426     struct dirent *dp;
[1705]427     DIR *dirp;
428     char first[MAXNAMLEN], rest[MAXPATHLEN];
[2175]429     int retval;
[2221]430     int strsize;
[3618]431     struct stat statbuf;
[3061]432#ifdef PATTERN_DEBUG
433     int j;
434#endif
[23667]435     int found_size = 0;
[1705]436     
[1732]437#ifdef DEBUG
[2221]438     printf("do_match: looking for %s\n", name);
[1732]439#endif
[2221]440
441     /* start: */
442     
443     if (*name == '/') {
444          *base = '/';
445          *(base + 1) = '\0';
446          name++;
447     }
448     else
449          *base = '\0';
450
[2365]451     *found = (char **) Malloc(0);
[2221]452     *num_found = 0;
453     
[2482]454     dirp = Opendir(base);
[2175]455     if (! dirp) {
456          set_error(errno);
457          error(base);
[3061]458#ifdef PATTERN_DEBUG
459          fprintf(stderr, "do_match: return 2.\n");
460#endif
[2175]461          return error_code;
462     }
[2221]463     (void) strcpy(first, firstpart(name, rest));
464     if ((! *first) && (match_undeleted)) {
[23667]465          retval = add_str(found, *num_found, &found_size, base);
[2221]466          if (retval) {
467               error("add_str");
468               (void) popall();
[3061]469#ifdef PATTERN_DEBUG
470               fprintf(stderr, "do_match: return 3.\n");
471#endif
[2221]472               return retval;
473          }
474          (*num_found)++;
[3061]475#ifdef PATTERN_DEBUG
476          fprintf(stderr, "do_match: return 4.\n");
477#endif
[2221]478          return 0;
479     }
480     
481     while (1) {
482          dp = readdir(dirp);
483          if (! dp) goto updir;
[1691]484
[2175]485          retval = reg_cmp(first, dp->d_name);
[3061]486#ifdef PATTERN_DEBUG
487        fprintf(stderr, "do_match: comparing %s to %s returns %d.\n",
488                first, dp->d_name, retval);
489#endif
[2175]490          if (retval < 0) {
491               error("reg_cmp");
[2221]492               goto updir;
[2175]493          }
494
[2221]495          if (retval == REGEXP_MATCH) goto downdir;
496
497          if (is_deleted(dp->d_name) && match_deleted) {
498               retval = reg_cmp(first, &dp->d_name[2]);
[3061]499#ifdef PATTERN_DEBUG
500               fprintf(stderr,
501                       "do_match: deleted compare of %s to %s returns %d.\n",
502                       first, &dp->d_name[2], retval);
503#endif
[2221]504               if (retval < 0) {
505                    error("reg_cmp");
506                    goto updir;
[1691]507               }
[2175]508
[2221]509               if (retval == REGEXP_MATCH)
510                    goto downdir;
511               else
512                    continue;
513          }
514          else
515               continue;
516
517     downdir:
[3061]518#ifdef PATTERN_DEBUG
519          fprintf(stderr, "do_match: downdir\n");
520#endif
[2221]521          retval = push(&dirp, sizeof(DIR *));
522          if (retval) {
523               error("push");
524               (void) popall();
[3061]525#ifdef PATTERN_DEBUG
526               fprintf(stderr, "do_match: return 5.\n");
527#endif
[2221]528               return retval;
529          }
[3061]530#ifdef PATTERN_DEBUG
531          fprintf(stderr, "do_match: pushing %s, %s, %s\n", first, rest, base);
532#endif
[2221]533          string_push(first);
534          string_push(rest);
535          string_push(base);
536          (void) strcpy(base, append(base, dp->d_name));
537          (void) strcpy(first, firstpart(rest, rest));
538          if (! *first) {
539               if (is_deleted(lastpart(base))) {
540                    if (match_deleted) {
[23667]541                         retval = add_str(found, *num_found, &found_size,
542                                          base);
[2221]543                         if (retval) {
544                              error("add_str");
545                              (void) popall();
[3061]546#ifdef PATTERN_DEBUG
547                              fprintf(stderr, "do_match: return 6.\n");
548#endif
[2221]549                              return retval;
550                         }
551                         (*num_found)++;
[2175]552                    }
[2221]553               }
554               else if (match_undeleted) {
[23667]555                    retval = add_str(found, *num_found, &found_size, base);
[2221]556                    if (retval) {
[2175]557                         error("add_str");
[2221]558                         (void) popall();
[3061]559#ifdef PATTERN_DEBUG
560                         fprintf(stderr, "do_match: return 7.\n");
561#endif
[2175]562                         return retval;
563                    }
[2221]564                    (*num_found)++;
[1691]565               }
[2221]566               string_pop(base);
567               string_pop(rest);
568               string_pop(first);
[3061]569#ifdef PATTERN_DEBUG
570               fprintf(stderr, "do_match: popped %s, %s, %s\n", first,
571                       rest, base);
572#endif
[2221]573               (void) pop(&dirp, sizeof(DIR *));
574               continue;
[1705]575          }
[3618]576
[6420]577          /*
578           * The logic here in this attempt to descend is as follows:
579           *
580           * Try to stat base.  Succeeds?
581           * Yes:
582           *   Is it a directory?
583           *   Yes:
584           *     Try to open it.
585           *     Does the open succeed?
586           *     Yes:
587           *       Continue the loop.
588           *     No:
589           *       Print an error, and pop up to the last directory.
590           *   No:
591           *     Pop up to the last directory.
592           * No:
593           *   Try to lstat base.  Succeeds?
594           *   Yes:
595           *     Is it a directory?
596           *     Yes: see above.  *** this should never happen ***
597           *     No:
598           *       Pop up to the last directory.
599           *   No:
600           *     Print an error, and pop up to the last directory.
601           *
602           * The reason for the lstat is that we don't want to print
603           * errors when we can't descend because we're trying to go
604           * into a symlink pointing nowhere; a symlink pointing
605           * nowhere is not an error when matching, it just means that
606           * we can't descend.
607           */
608          dirp = NULL;
609          if (((! (retval = stat(base, &statbuf))) ||
610               (! (retval = lstat(base, &statbuf)))) &&
611              ((statbuf.st_mode & S_IFMT) == S_IFDIR))
612               dirp = Opendir(base);
[2221]613          if (! dirp) {
[6420]614               if (retval || ((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
615                    set_error(errno);
616                    error(base);
617               }
[2221]618               string_pop(base);
619               string_pop(rest);
620               string_pop(first);
[3061]621#ifdef PATTERN_DEBUG
622               fprintf(stderr, "do_match: popped %s, %s, %s\n", first,
623                       rest, base);
624#endif
[2221]625               (void) pop(&dirp, sizeof(DIR *));
626               continue;
627          }
628          else
629               continue;
[2175]630
[2221]631     updir:
[3061]632#ifdef PATTERN_DEBUG
633          fprintf(stderr, "do_match: updir\n");
634#endif
[2221]635          closedir(dirp);
636          string_pop(base);
[3061]637#ifdef PATTERN_DEBUG
638          fprintf(stderr, "do_match: popped %s\n", base);
639#endif
[2221]640          if (retval) {
641               if (retval != STACK_EMPTY) {
642                    error("pop");
643                    (void) popall();
[3061]644#ifdef PATTERN_DEBUG
645                    fprintf(stderr, "do_match: return 8.\n");
646#endif
[2221]647                    return retval;
[1691]648               }
[3061]649#ifdef PATTERN_DEBUG
650               fprintf(stderr, "Returning %d word%s from do_match:\n",
651                       *num_found,
652                       *num_found == 1 ? "" : "s");
653               for (j = 0; j < *num_found; j++)
654                    fprintf(stderr, "\t%s\n", (*found)[j]);
655               fprintf(stderr, "do_match: return 9.\n");
656#endif
[2221]657               return 0;
[1691]658          }
[2221]659          string_pop(rest);
660          string_pop(first);
[3061]661#ifdef PATTERN_DEBUG
662          fprintf(stderr, "do_match: popped %s, %s\n", rest, first);
663#endif
[2221]664          retval = pop(&dirp, sizeof(DIR *));
665          if (retval) {
666               error("pop");
667               (void) popall();
[3061]668#ifdef PATTERN_DEBUG
669               fprintf(stderr, "do_match: return 10.\n");
670#endif
[2221]671               return retval;
672          }
673          continue;
[1691]674     }
675}
676
[1705]677
678
679
680
681
[2221]682/*
683 * Function: do_recurs(char *name, int *num_found, char ***found,
684 *                     int options)
685 *
686 * Requires: name points to a NULL-terminated string, representing a
[4404]687 *   filename; points to a valid int memory storage location; found
688 *   points to a valid char ** memory storage location.
[2221]689 *
690 * Effects: Returns a list of all the files in the file hierarchy that
691 *   are underneath the specified file, governed by the options set in
692 *   options.  Options are as described in the find_matches() description.
693 *   RECURS_FIND_DELETED and RECURS_DELETED imply FIND_DELETED.
694 *   RECURS_FIND_UNDELETED implies FIND_UNDELETED.
695 *
696 * Modifies: *num_found, *found.
697 *
698 * Algorithm:
699 *
700 * start:
701 *   initialze found and num_found
702 *   strcopy(base, name)
[3618]703 *   check if we just opened a deleted symlink and return if we did
[2482]704 *   dirp = Opendir(base)
[2221]705 *   check RECURS options and set FIND options as appropriate
706 *
707 * loop:
708 *   dp = readdir(dirp)
709 *   if (! dp) goto updir
710 *   is dp deleted?
711 *     yes - is FIND_DELETED set?
712 *             yes - add to list
713 *                   is RECURS_DELETED set?
714 *                     yes - goto downdir
715 *                     no - goto loop
716 *             no - goto loop
717 *     no - is FIND_UNDELETED set?
718 *            yes - is the file a dotfile?
719 *                    yes - is FIND_DOTFILES set?
720 *                            yes - add to list
721 *                          goto loop
722 *                    no - add to list
723 *                  are RECURS_FIND_DELETED and FIND_DELETED set?
724 *                    yes - goto downdir
725 *                  is RECURS_FIND_UNDELETED set?
726 *                    yes - goto downdir
727 *                    no - goto loop
728 *            no - goto loop
729 *             
730 * downdir:
731 *   save dirp, base on stack
732 *   base = dp->d_name appended to base
733 *   try to open base -- opens?
734 *     yes - is FOLLW_LINKS set?
735 *             yes - is it deleted?
736 *                   yes - is it a link?
737 *                         yes - close the directory
738 *                               restore base and dirp
739 *                               goto loop
740 *             no - is it a link?
741 *                     yes - close the directory
742 *                           restore base and dirp
743 *                           goto loop
744 *           is FOLLW_MOUNTPOINTS set?
745 *             no - is it a mountpoint?
746 *                     yes - close the directory
747 *                           restore base and dirp
748 *                           goto loop
749 *     no - is the error ENOTDIR?
750 *            yes - don't worry about it
751 *            no - report the error
752 *          restore base and dirp
753 *          goto loop
754 *
755 * updir:
756 *   close dirp
757 *   restore base from stack
758 *   STACK_EMPTY?
759 *     yes - return from procedure with results
760 *   restore dirp from stack
761 *   goto loop
762 */
763int do_recurs(name, num_found, found, options)
764char *name;
[1705]765int *num_found;
[2175]766char ***found;
[2221]767int options;
[1691]768{
[2221]769     char base[MAXPATHLEN];
[5138]770     struct dirent *dp;
[1705]771     DIR *dirp;
[2175]772     int retval;
[2221]773     int strsize;
774     struct stat statbuf;
775     int use_stat;
[23667]776     int found_size = 0;
[4404]777
[1732]778#ifdef DEBUG
[2377]779     fprintf(stderr, "do_recurs: opening %s\n", name);
[1732]780#endif
[2221]781
782     /* start: */
783     
[2365]784     *found = (char **) Malloc(0);
[2221]785     *num_found = 0;
786     strcpy(base, name);
[3618]787
[4404]788     if (lstat(base, &statbuf)) {
[3618]789          set_error(errno);
790          error(base);
791          return error_code;
792     }
793         
[23666]794#ifdef S_IFLNK
[4404]795     if (is_link(base, &statbuf)) {
796          /* Never follow deleted symlinks */
797          if (is_deleted(lastpart(base))) {
798               return 0;
799          }
800          if (stat(base, &statbuf)) {
801               if (errno == ENOENT) {
802                    extern int readlink();
803                    char pathbuf[MAXPATHLEN];
804                    int cc;
805                   
806                    /* What the link is pointing to does not exist; */
807                    /* this is a warning, not an error.             */
808                    set_warning(errno);
809                    cc = readlink(base, pathbuf, MAXPATHLEN);
810                    if (cc > 0) {
811                         char error_buf[2*MAXPATHLEN+20];
812
813                         pathbuf[(cc == MAXPATHLEN) ? (cc - 1) : cc] = '\0';
814                         sprintf(error_buf, "%s (pointed to by %s)", pathbuf,
815                                 base);
816                         error(error_buf);
817                    }
818                    else {
819                         error(base);
820                    }
821
822                    return 0;
823               }
824               else {
825                    set_error(errno);
826                    error(base);
827                    return error_code;
828               }
829          }
[2221]830     }
[23666]831#endif
[3618]832
833     if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
834          return 0;
[2221]835     
[2482]836     dirp = Opendir(base);
[2175]837     if (! dirp) {
[2377]838#ifdef DEBUG
[3618]839          fprintf(stderr, "Couldn't open %s.\n", base);
[2377]840#endif
[3618]841          set_error(errno);
842          error(base);
843          return error_code;
[1705]844     }
845
[2221]846     if (options & (RECURS_FIND_DELETED | RECURS_DELETED))
847          options |= FIND_DELETED;
848     if (options & RECURS_FIND_UNDELETED)
849          options |= FIND_UNDELETED;
[1691]850     
[2221]851     while (1) {
852          dp = readdir(dirp);
853          if (! dp) goto updir;
[1691]854
[2221]855          if (is_deleted(dp->d_name)) {
856               if (options & FIND_DELETED) {
[23667]857                    retval = add_str(found, *num_found, &found_size,
[2221]858                                     append(base, dp->d_name));
859                    if (retval) {
860                         error("add_str");
861                         (void) popall();
862                         return retval;
863                    }
864                    (*num_found)++;
865                    if (options & RECURS_DELETED)
866                         goto downdir;
867                    else
868                         continue;
869               }
870               else
871                    continue;
872          }
[1705]873
[2221]874          if (options & FIND_UNDELETED) {
875               if (is_dotfile(dp->d_name)) {
876                    if (options & FIND_DOTFILES) {
[23667]877                         retval = add_str(found, *num_found, &found_size,
[2221]878                                          append(base, dp->d_name));
879                         if (retval) {
880                              error("add_str");
881                              (void) popall();
882                              return retval;
883                         }
884                    }
885                    continue;
886               }
887               else {
[23667]888                    retval = add_str(found, *num_found, &found_size,
[2221]889                                     append(base, dp->d_name));
890                    if (retval) {
891                         error("add_str");
892                         (void) popall();
893                         return retval;
894                    }
895                    (*num_found)++;
896               }
897          }
[2175]898
[2221]899          if (! is_dotfile(dp->d_name)) {
900               if (options & RECURS_FIND_DELETED)
901                    goto downdir;
902               if (options & RECURS_FIND_UNDELETED)
903                    goto downdir;
[2175]904          }
[1705]905         
[2221]906          continue;
907         
908               
909     downdir:
910          retval = push(&dirp, sizeof(DIR *));
911          if (retval) {
912               error("push");
913               (void) popall();
914               return retval;
[1691]915          }
[2221]916          string_push(base);
917          (void) strcpy(base, append(base, dp->d_name));
918
919          /*
[2482]920           * Originally, I did an Opendir() right at the start and
921           * then only checked things if the Opendir resulted in an
[2221]922           * error.  However, this is inefficient, because the
[2482]923           * Opendir() procedure works by first calling open() on the
[2221]924           * file, and *then* calling fstat on the file descriptor
925           * that is returned.  since most of the time we will be
926           * trying to open things that are not directory, it is much
927           * more effecient to do the stat first here and to do the
[2482]928           * Opendir only if the stat results are satisfactory.
[2221]929           */
930          use_stat = (options & FOLLW_LINKS) && (! is_deleted(lastpart(base)));
931          if (use_stat)
932               retval = stat(base, &statbuf);
933          else
934               retval = lstat(base, &statbuf);
935          if (retval == -1) {
[2175]936               set_error(errno);
[2221]937               error(base);
938               string_pop(base);
939               (void) pop(&dirp, sizeof(DIR *));
[1691]940               continue;
[1705]941          }
[2221]942          /* It's not a directory, so punt it and continue. */
943          if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
944               string_pop(base);
945               (void) pop(&dirp, sizeof(DIR *));
946               continue;
947          }
948
949          /* Actually try to open it. */
[2482]950          dirp = Opendir(base);
[2221]951          if (! dirp) {
952               set_error(errno);
953               error(base);
954               string_pop(base);
955               (void) pop(&dirp, sizeof(DIR *));
956               continue;
957          }
958         
959          if (! (options & FOLLW_MOUNTPOINTS)) {
960               if (is_mountpoint(base, use_stat ? (struct stat *) NULL :
961                                 &statbuf)) {
[2175]962                    closedir(dirp);
[2221]963                    set_warning(PAT_IS_MOUNT);
964                    error(base);
965                    string_pop(base);
966                    (void) pop(&dirp, sizeof(DIR *));
967                    continue;
[2175]968               }
[2582]969#ifdef DEBUG
970               else {
971                    fprintf(stderr,
972                            "do_recurs: %s isn't a mountpoint, following.\n",
973                            base);
974               }
975#endif
[1691]976          }
[1732]977#ifdef DEBUG
[2582]978          printf("do_recurs: opening %s\n", base);
[1732]979#endif
[2221]980          continue;
981         
982     updir:
983          closedir(dirp);
984          string_pop(base);
985          if (retval) {
986               if (retval != STACK_EMPTY) {
987                    error("pop");
988                    (void) popall();
989                    return retval;
990               }
991               return 0;
[2175]992          }
[2221]993          retval = pop(&dirp, sizeof(DIR *));
994          if (retval) {
995               error("pop");
996               (void) popall();
[2175]997               return retval;
998          }
[2221]999          continue;
[1705]1000     }
1001}
1002
1003
[2221]1004void free_list(list, num)
1005char **list;
1006int num;
[1705]1007{
[2221]1008     int i;
[1705]1009
[2221]1010     for (i = 0; i < num; i++)
1011          free(list[i]);
[2175]1012
[2221]1013     free((char *) list);
[1705]1014}
1015
1016
1017
1018
[1756]1019
1020
1021/*
[2175]1022 * returns true if the filename has no globbing wildcards in it.  That
1023 * means no non-quoted question marks, asterisks, or open square
1024 * braces.  Assumes a null-terminated string, and a valid globbing
[1756]1025 */
1026int no_wildcards(name)
1027char *name;
1028{
1029     do {
1030          switch (*name) {
1031          case '\\':
1032               name++;
1033               break;
[2175]1034          case '?':
[1756]1035               return(0);
1036          case '*':
1037               return(0);
[2175]1038          case '[':
1039               return(0);
[1756]1040          }
1041     } while (*++name);
1042     return(1);
1043}
Note: See TracBrowser for help on using the repository browser.