/* Take a "mode" indicator and fill in the files of 'state'. */ int digest_mode(mode_t mode, const char *pathname, const char *name, struct stat *pstat, boolean leaf) { /* If we know the type of the directory entry, and it is not a * symbolic link, we may be able to avoid a stat() or lstat() call. */ if (mode) { if (S_ISLNK(mode) && following_links()) { /* mode is wrong because we should have followed the symlink. */ if (get_statinfo(pathname, name, pstat) != 0) return 0; mode = state.type = pstat->st_mode; state.have_type = true; } else { state.have_type = true; pstat->st_mode = state.type = mode; } } else { /* Mode is not yet known; may have to stat the file unless we * can deduce that it is not a directory (which is all we need to * know at this stage) */ if (leaf) { state.have_stat = false; state.have_type = false;; state.type = 0; } else { if (get_statinfo(pathname, name, pstat) != 0) return 0; /* If -L is in effect and we are dealing with a symlink, * st_mode is the mode of the pointed-to file, while mode is * the mode of the directory entry (S_IFLNK). Hence now * that we have the stat information, override "mode". */ state.type = pstat->st_mode; state.have_type = true; } } /* success. */ return 1; }
/* Get the stat/type information for a file, if it is * not already known. */ int get_info (const char *pathname, struct stat *p, struct predicate *pred_ptr) { boolean todo = false; /* If we need the full stat info, or we need the type info but don't * already have it, stat the file now. */ if (pred_ptr->need_stat) todo = true; else if ((pred_ptr->need_type && (0 == state.have_type))) todo = true; if (todo) return get_statinfo(pathname, state.rel_pathname, p); else return 0; }
static int process_path (char *pathname, char *name, bool leaf, char *parent, mode_t mode, ino_t inum) { struct stat stat_buf; static dev_t root_dev; /* Device ID of current argument pathname. */ int i; struct predicate *eval_tree; eval_tree = get_eval_tree (); /* Assume it is a non-directory initially. */ stat_buf.st_mode = 0; /* The caller usually knows the inode number, either from readdir or * a *stat call. We use that value (the caller passes 0 to indicate * ignorance of the inode number). */ stat_buf.st_ino = inum; state.rel_pathname = name; state.type = 0; state.have_stat = false; state.have_type = false; state.already_issued_stat_error_msg = false; if (!digest_mode (&mode, pathname, name, &stat_buf, leaf)) return 0; if (!S_ISDIR (state.type)) { if (state.curdepth >= options.mindepth) apply_predicate (pathname, &stat_buf, eval_tree); return 0; } /* From here on, we're working on a directory. */ /* Now we really need to stat the directory, even if we know the * type, because we need information like struct stat.st_rdev. */ if (get_statinfo (pathname, name, &stat_buf) != 0) return 0; state.have_stat = true; mode = state.type = stat_buf.st_mode; /* use full info now that we have it. */ state.stop_at_current_level = options.maxdepth >= 0 && state.curdepth >= options.maxdepth; /* If we've already seen this directory on this branch, don't descend it again. */ for (i = 0; i <= dir_curr; i++) if (stat_buf.st_ino == dir_ids[i].ino && stat_buf.st_dev == dir_ids[i].dev) { state.stop_at_current_level = true; issue_loop_warning (name, pathname, i); } if (dir_alloc <= ++dir_curr) { dir_alloc += DIR_ALLOC_STEP; dir_ids = (struct dir_id *) xrealloc ((char *) dir_ids, dir_alloc * sizeof (struct dir_id)); } dir_ids[dir_curr].ino = stat_buf.st_ino; dir_ids[dir_curr].dev = stat_buf.st_dev; if (options.stay_on_filesystem) { if (state.curdepth == 0) root_dev = stat_buf.st_dev; else if (stat_buf.st_dev != root_dev) state.stop_at_current_level = true; } if (options.do_dir_first && state.curdepth >= options.mindepth) apply_predicate (pathname, &stat_buf, eval_tree); if (options.debug_options & DebugSearch) fprintf (stderr, "pathname = %s, stop_at_current_level = %d\n", pathname, state.stop_at_current_level); if (state.stop_at_current_level == false) { /* Scan directory on disk. */ process_dir (pathname, name, strlen (pathname), &stat_buf, parent); } if (options.do_dir_first == false && state.curdepth >= options.mindepth) { /* The fields in 'state' are now out of date. Correct them. */ if (!digest_mode (&mode, pathname, name, &stat_buf, leaf)) return 0; if (0 == dir_curr) { at_top (pathname, mode, stat_buf.st_ino, &stat_buf, do_process_predicate); } else { do_process_predicate (pathname, name, mode, stat_buf.st_ino, &stat_buf); } } dir_curr--; return 1; }